configure.ac: add libusb/libusbx support (for xpp)
[dahdi/tools.git] / xpp / astribank_usb.c
1 /*
2  * Written by Oron Peled <oron@actcom.co.il>
3  * Copyright (C) 2008, 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 #define _GNU_SOURCE     /* for memrchr() */
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <stdarg.h>
31 #include <syslog.h>
32 #include <arpa/inet.h>
33 #include <xusb.h>
34 #include "astribank_usb.h"
35 #include <debug.h>
36
37 static const char rcsid[] = "$Id$";
38
39 #define DBG_MASK        0x01
40 #define TIMEOUT 500
41
42 #define TYPE_ENTRY(t,p,ni,n,ne,out,in,...)      \
43                 {                               \
44                 .my_vendor_id = 0xe4e4,         \
45                 .my_product_id = (p),           \
46                 .name = #t,                     \
47                 .num_interfaces = (ni),         \
48                 .my_interface_num = (n),        \
49                 .num_endpoints = (ne),          \
50                 .my_ep_in = (in),               \
51                 .my_ep_out = (out),             \
52                 }
53
54 #define ARRAY_SIZE(x)   (sizeof(x)/sizeof(x[0]))
55
56 static const struct xusb_spec   astribank_specs[] = {
57         /* OLD Firmwares */
58         TYPE_ENTRY("USB-OLDFXS",        0x1131, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
59         TYPE_ENTRY("FPGA-OLDFXS",       0x1132, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
60         TYPE_ENTRY("USB-BRI",           0x1141, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
61         TYPE_ENTRY("FPGA-BRI",          0x1142, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
62         TYPE_ENTRY("USB-OLD",           0x1151, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
63         TYPE_ENTRY("FPGA-OLD",          0x1152, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
64
65         TYPE_ENTRY("USB-MULTI",         0x1161, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
66         TYPE_ENTRY("FPGA-MULTI",        0x1162, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
67         TYPE_ENTRY("BURNED-MULTI",      0x1164, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
68         TYPE_ENTRY("USB-BURN",          0x1112, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
69 };
70
71 static const struct xusb_spec   astribank_pic_specs[] = {
72         TYPE_ENTRY("USB_PIC",           0x1161, 2, 0, 2, XPP_EP_OUT, XPP_EP_IN),
73 };
74 #undef TYPE_ENTRY
75
76 //static int    verbose = LOG_DEBUG;
77
78 /*
79  * USB handling
80  */
81 struct astribank_device *astribank_open(const char devpath[], int iface_num)
82 {
83         struct astribank_device *astribank = NULL;
84         struct xusb             *xusb;
85
86         DBG("devpath='%s' iface_num=%d\n", devpath, iface_num);
87         if((astribank = malloc(sizeof(struct astribank_device))) == NULL) {
88                 ERR("Out of memory\n");
89                 goto fail;
90         }
91         memset(astribank, 0, sizeof(*astribank));
92         if (iface_num) {
93                 xusb  = xusb_find_bypath(astribank_specs, ARRAY_SIZE(astribank_specs), devpath);
94         } else {
95                 xusb  = xusb_find_bypath(astribank_pic_specs, ARRAY_SIZE(astribank_pic_specs), devpath);
96         }
97         if (!xusb) {
98                 ERR("%s: No device found\n", __func__);
99                 goto fail;
100         }
101         astribank->xusb = xusb;
102         astribank->is_usb2 = (xusb_packet_size(xusb) == 512);
103         astribank->my_interface_num = iface_num;
104         if (xusb_claim_interface(astribank->xusb) < 0) {
105                 ERR("xusb_claim_interface failed\n");
106                 goto fail;
107         }
108         astribank->tx_sequenceno = 1;
109         return astribank;
110 fail:
111         if (astribank) {
112                 free(astribank);
113                 astribank = NULL;
114         }
115         return NULL;
116 }
117
118 /*
119  * MP device handling
120  */
121 void show_astribank_info(const struct astribank_device *astribank)
122 {
123         struct xusb                     *xusb;
124
125         assert(astribank != NULL);
126         xusb = astribank->xusb;
127         assert(xusb != NULL);
128         if(verbose <= LOG_INFO) {
129                 xusb_showinfo(xusb);
130         } else {
131                 const struct xusb_spec  *spec;
132
133                 spec = xusb_spec(xusb);
134                 printf("USB    Bus/Device:    [%s]\n", xusb_devpath(xusb));
135                 printf("USB    Firmware Type: [%s]\n", spec->name);
136                 printf("USB    iSerialNumber: [%s]\n", xusb_serial(xusb));
137                 printf("USB    iManufacturer: [%s]\n", xusb_manufacturer(xusb));
138                 printf("USB    iProduct:      [%s]\n", xusb_product(xusb));
139         }
140 }
141
142 void astribank_close(struct astribank_device *astribank, int disconnected)
143 {
144         assert(astribank != NULL);
145         if (astribank->xusb) {
146                 xusb_close(astribank->xusb);
147                 astribank->xusb = NULL;
148         }
149         astribank->tx_sequenceno = 0;
150 }
151
152 #if 0
153 int flush_read(struct astribank_device *astribank)
154 {
155         char            tmpbuf[BUFSIZ];
156         int             ret;
157
158         DBG("starting...\n");
159         memset(tmpbuf, 0, BUFSIZ);
160         ret = recv_usb(astribank, tmpbuf, BUFSIZ, 1);
161         if(ret < 0 && ret != -ETIMEDOUT) {
162                 ERR("ret=%d\n", ret);
163                 return ret;
164         } else if(ret > 0) {
165                 DBG("Got %d bytes:\n", ret);
166                 dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, tmpbuf, ret);
167         }
168         return 0;
169 }
170 #endif
171
172
173 int release_isvalid(uint16_t release)
174 {
175         uint8_t rmajor = (release >> 8) & 0xFF;
176         uint8_t rminor = release & 0xFF;
177
178         return  (rmajor > 0) &&
179                 (rmajor < 10) &&
180                 (rminor > 0) &&
181                 (rminor < 10);
182 }
183
184 int label_isvalid(const char *label)
185 {
186         int             len;
187         int             goodlen;
188         const char      GOOD_CHARS[] =
189                                 "abcdefghijklmnopqrstuvwxyz"
190                                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
191                                 "0123456789"
192                                 "-_.";
193
194         len = strlen(label);
195         goodlen = strspn(label, GOOD_CHARS);
196         if(len > LABEL_SIZE) {
197                 ERR("Label too long (%d > %d)\n", len, LABEL_SIZE);
198                 return 0;
199         }
200         if(goodlen != len) {
201                 ERR("Bad character in label (pos=%d)\n", goodlen);
202                 return 0;
203         }
204         return 1;
205 }
206
207 int eeprom_fill(struct eeprom_table *eprm,
208         const char *vendor,
209         const char *product,
210         const char *release,
211         const char *label)
212 {
213         uint16_t        val;
214
215         eprm->source = 0xC0;
216         eprm->config_byte = 0;
217         if(vendor) {
218                 val = strtoul(vendor, NULL, 0);
219                 if(!val) {
220                         ERR("Invalid vendor '%s'\n",
221                                 vendor);
222                         return -EINVAL;
223                 }
224                 eprm->vendor = val;
225         }
226         if(product) {
227                 val = strtoul(product, NULL, 0);
228                 if(!val) {
229                         ERR("Invalid product '%s'\n",
230                                 product);
231                         return -EINVAL;
232                 }
233                 eprm->product = val;
234         }
235         if(release) {
236                 int             release_major = 0;
237                 int             release_minor = 0;
238                 uint16_t        value;
239
240                 if(sscanf(release, "%d.%d", &release_major, &release_minor) != 2) {
241                         ERR("Failed to parse release number '%s'\n", release);
242                         return -EINVAL;
243                 }
244                 value = (release_major << 8) | release_minor;
245                 DBG("Parsed release(%d): major=%d, minor=%d\n",
246                         value, release_major, release_minor);
247                 if(!release_isvalid(value)) {
248                         ERR("Invalid release number 0x%X\n", value);
249                         return -EINVAL;
250                 }
251                 eprm->release = value;
252         }
253         if(label) {
254                 /* padding */
255                 if(!label_isvalid(label)) {
256                         ERR("Invalid label '%s'\n", label);
257                         return -EINVAL;
258                 }
259                 memset(eprm->label, 0, LABEL_SIZE);
260                 memcpy(eprm->label, label, strlen(label));
261         }
262         return 0;
263 }
264
265 int astribank_has_twinstar(struct astribank_device *astribank)
266 {
267         uint16_t                        product_series;
268
269         assert(astribank != NULL);
270         product_series = xusb_product_id(astribank->xusb);
271         product_series &= 0xFFF0;
272         if(product_series == 0x1160)    /* New boards */
273                 return 1;
274         return 0;
275 }
276