1 /*
2 OWFS -- One-Wire filesystem
3 OWHTTPD -- One-Wire Web Server
4 Written 2003 Paul H Alfille
5 email: paul.alfille@gmail.com
6 Released under the GPL
7 See the header file: ow.h for full attribution
8 1wire/iButton system from Dallas Semiconductor
9 */
10
11 /* DS9490R-W USB 1-Wire master
12
13 USB parameters:
14 Vendor ID: 04FA
15 ProductID: 2490
16
17 Dallas controller DS2490
18
19 */
20
21 #include <config.h>
22 #include "owfs_config.h"
23 #include "ow.h"
24 #include "ow_connection.h"
25 #include "ow_usb_cycle.h"
26 #include "ow_usb_msg.h"
27
28 #if OW_USB /* conditional inclusion of USB */
29
30 #define CONTROL_REQUEST_TYPE 0x40
31
32 /** EP1 -- control read */
33 #define DS2490_EP1 0x81
34 /** EP2 -- bulk write */
35 #define DS2490_EP2 0x02
36 /** EP3 -- bulk read */
37 #define DS2490_EP3 0x83
38
39 char badUSBname[] = "-1:-1";
40
41 static int usb_transfer( int (*transfer_function) (struct libusb_device_handle *dev_handle, unsigned char endpoint, BYTE *data, int length, int *transferred, unsigned int timeout), unsigned char endpoint, BYTE * data, int length, int * transferred, struct connection_in * in ) ;
42 static void usb_buffer_traffic( BYTE * buffer ) ;
43
44 /* ------------------------------------------------------------ */
45 /* --- USB low-level communication -----------------------------*/
46
47 // Call to USB EP1 (control channel)
48 // Names (bRequest, wValue wIndex) are from datasheet http://datasheets.maxim-ic.com/en/ds/DS2490.pdf
49 // libusb version.
USB_Control_Msg(BYTE bRequest,UINT wValue,UINT wIndex,const struct parsedname * pn)50 GOOD_OR_BAD USB_Control_Msg(BYTE bRequest, UINT wValue, UINT wIndex, const struct parsedname *pn)
51 {
52 struct connection_in * in = pn->selected_connection ;
53 libusb_device_handle *usb = in->master.usb.lusb_handle;
54 int ret ;
55 if (usb == NULL) {
56 return gbBAD;
57 }
58 ret = libusb_control_transfer(usb, CONTROL_REQUEST_TYPE, bRequest, wValue, wIndex, NULL, 0, in->master.usb.timeout);
59 if (Globals.traffic) {
60 fprintf(stderr, "TRAFFIC OUT <control> bus=%d (%s)\n", in->index, DEVICENAME(in) ) ;
61 fprintf(stderr, "\tbus name=%s request type=0x%.2X, wValue=0x%X, wIndex=0x%X, return code=%d\n",in->adapter_name, bRequest, wValue, wIndex, ret) ;
62 }
63 if( ret < 0 ) {
64 LEVEL_DEBUG("<%s> USB control problem", libusb_error_name(ret)) ;
65 return gbBAD ;
66 }
67 return gbGOOD ;
68 }
69
DS9490_getstatus(BYTE * buffer,int * readlen,const struct parsedname * pn)70 RESET_TYPE DS9490_getstatus(BYTE * buffer, int * readlen, const struct parsedname *pn)
71 {
72 int ret ;
73 int loops = 0;
74 struct connection_in * in = pn->selected_connection ;
75 int transferred ;
76
77 memset(buffer, 0, DS9490_getstatus_BUFFER_LENGTH ); // should not be needed
78
79 do {
80 ret = usb_transfer( libusb_interrupt_transfer, DS2490_EP1, buffer, DS9490_getstatus_BUFFER_LENGTH, &transferred, in ) ;
81
82 if ( ret < 0 ) {
83 LEVEL_DATA("<%s> USB_INTERRUPT_READ error reading", libusb_error_name(ret));
84 STAT_ADD1_BUS(e_bus_status_errors, in);
85 return BUS_RESET_ERROR;
86 } else if (transferred > DS9490_getstatus_BUFFER_LENGTH ) {
87 LEVEL_DATA("Bad DS2490 status %d > 32",transferred) ;
88 return BUS_RESET_ERROR;
89 } else if ( transferred > DS9490_getstatus_BUFFER ) {
90 int i ;
91 if ( transferred == DS9490_getstatus_BUFFER_LENGTH ) { // FreeBSD buffers the input, so this could just be two readings
92 if (!memcmp(buffer, &buffer[DS9490_getstatus_BUFFER], 6)) {
93 memmove(buffer, &buffer[DS9490_getstatus_BUFFER], DS9490_getstatus_BUFFER);
94 transferred = DS9490_getstatus_BUFFER;
95 LEVEL_DATA("Corrected buffer 32 byte read");
96 }
97 }
98 for (i = DS9490_getstatus_BUFFER; i < transferred; i++) {
99 BYTE val = buffer[i];
100 if (val != ONEWIREDEVICEDETECT) {
101 LEVEL_DATA("Status byte[%X]: %X", i - DS9490_getstatus_BUFFER, val);
102 }
103 if (val & COMMCMDERRORRESULT_SH) { // short detected
104 LEVEL_DATA("short detected");
105 return BUS_RESET_SHORT;
106 }
107 }
108 }
109
110 if (readlen[0] < 0) {
111 break; /* Don't wait for STATUSFLAGS_IDLE if length==-1 */
112 }
113
114 usb_buffer_traffic( buffer ) ;
115 if (buffer[8] & STATUSFLAGS_IDLE) {
116 if (readlen[0] > 0) {
117 // we have enough bytes to read now!
118 // buffer[13] == (ReadBufferStatus)
119 if (buffer[13] >= readlen[0]) {
120 break;
121 }
122 LEVEL_DEBUG("Problem with buffer[13]=%d and readlen[0]=%d",(int) buffer[13], (int) readlen[0] ) ;
123 } else {
124 break;
125 }
126 }
127 // this value might be decreased later...
128 if (++loops > 100) {
129 LEVEL_DATA("never got idle StatusFlags=%X read=%X", buffer[8], buffer[13]);
130 //reset USB device
131 // probably should reset speed and any other parameters.
132 USB_Control_Msg(CONTROL_CMD, CTL_RESET_DEVICE, 0x0000, pn) ;
133 return BUS_RESET_ERROR; // adapter never got idle
134 }
135 /* Since result seem to be on the usb bus very quick, I sleep
136 * sleep 0.1ms or something like that instead... It seems like
137 * result is there after 0.2-0.3ms
138 */
139 UT_delay_us(100);
140 } while (1);
141
142 if (transferred < DS9490_getstatus_BUFFER) {
143 LEVEL_DATA("incomplete packet size=%d", transferred);
144 return BUS_RESET_ERROR; // incomplete packet??
145 }
146 readlen[0] = transferred ; // pass this data back (used by reset)
147 return BUS_RESET_OK ;
148 }
149
usb_buffer_traffic(BYTE * buffer)150 static void usb_buffer_traffic( BYTE * buffer )
151 {
152 if (Globals.traffic) {
153 // See note below for register info
154 LEVEL_DEBUG("USB status registers (Idle) EFlags:%u->SPU:%u Dspeed:%u,Speed:%u,SPUdur:%u, PDslew:%u, W1lowtime:%u, W0rectime:%u, DevState:%u, CC1:%u, CC2:%u, CCState:%u, DataOutState:%u, DataInState:%u",
155 buffer[0], (buffer[0]&0x01), (buffer[0]&0x04 ? 1 : 0),
156 buffer[1],
157 buffer[2],
158 buffer[4],
159 buffer[5],
160 buffer[6],
161 buffer[8],
162 buffer[9],
163 buffer[10],
164 buffer[11],
165 buffer[12],
166 buffer[13]
167 );
168 }
169 }
170
171
172 // libusb version
173 // dev already set
DS9490_open(struct connection_in * in)174 GOOD_OR_BAD DS9490_open( struct connection_in *in )
175 {
176 libusb_device_handle * usb ;
177 libusb_device * dev = in->master.usb.lusb_dev ;
178 int usb_err ;
179
180 if ( dev == NULL ) {
181 return gbBAD ;
182 }
183
184 if ( (usb_err=libusb_open( dev, &usb )) != 0 ) {
185 // intentional print to console
186 fprintf(stderr, "<%s> Could not open the USB bus master. Is there a problem with permissions?\n",libusb_error_name(usb_err));
187 // And log
188 LEVEL_DEFAULT("<%s> Could not open the USB bus master. Is there a problem with permissions?",libusb_error_name(usb_err));
189 STAT_ADD1_BUS(e_bus_open_errors, in);
190 return gbBAD ;
191 }
192
193 in->master.usb.lusb_handle = usb;
194 in->master.usb.bus_number = libusb_get_bus_number( dev ) ;
195 in->master.usb.address = libusb_get_device_address( dev ) ;
196 // if ( libusb_set_auto_detach_kernel_driver( usb, 1) != 0 ) {
197 // LEVEL_CONNECT( "Could not set automatic USB driver management option" ) ;
198 // }
199 if ( (usb_err=libusb_detach_kernel_driver( usb, 0))!= 0 ) {
200 LEVEL_DEBUG( "<%s> Could not release kernel module",libusb_error_name(usb_err) ) ;
201 }
202
203 // store timeout value -- sec -> msec
204 in->master.usb.timeout = 1000 * Globals.timeout_usb;
205
206 if ( (usb_err=libusb_set_configuration(usb, 1)) != 0 ) {
207 LEVEL_CONNECT("<%s> Failed to set configuration on USB DS9490 bus master at %s", libusb_error_name(usb_err), DEVICENAME(in) );
208 } else if ( (usb_err=libusb_claim_interface(usb, 0)) != 0 ) {
209 LEVEL_CONNECT("<%s> Failed to claim interface on USB DS9490 bus master at %s", libusb_error_name(usb_err), DEVICENAME(in) );
210 } else {
211 if ( (usb_err=libusb_set_interface_alt_setting(usb, 0, 3)) != 0 ) {
212 LEVEL_CONNECT("<%s> Failed to set alt interface on USB DS9490 bus master at %s", libusb_error_name(usb_err), DEVICENAME(in) );
213 } else {
214 LEVEL_DEFAULT("Opened USB DS9490 bus master at %s.", DEVICENAME(in));
215
216 // clear endpoints
217 if ( (usb_err=libusb_clear_halt(usb, DS2490_EP3)) || (usb_err=libusb_clear_halt(usb, DS2490_EP2)) || (usb_err=libusb_clear_halt(usb, DS2490_EP1)) ) {
218 LEVEL_DEFAULT("<%s> USB_CLEAR_HALT failed",libusb_error_name(usb_err));
219 } else { /* All GOOD */
220 return gbGOOD;
221 }
222 }
223 if ((usb_err=libusb_release_interface(usb, 0)) != 0 ) {
224 LEVEL_DEBUG("<%s>",libusb_error_name(usb_err)) ;
225 }
226 if ((usb_err=libusb_attach_kernel_driver( usb,0 )) != 0 ) {
227 LEVEL_DEBUG("<%s>",libusb_error_name(usb_err));
228 }
229 }
230 libusb_close(usb);
231 in->master.usb.lusb_dev = NULL;
232
233 LEVEL_DEBUG("Did not successfully open DS9490 %s -- permission problem?",DEVICENAME(in)) ;
234 STAT_ADD1_BUS(e_bus_open_errors, in);
235 return gbBAD;
236 }
237
DS9490_close(struct connection_in * in)238 void DS9490_close(struct connection_in *in)
239 {
240 libusb_device_handle *usb = in->master.usb.lusb_handle;
241
242 if (usb != NULL) {
243 int ret = libusb_release_interface(usb, 0);
244 if ( ret != 0 ) {
245 in->master.usb.lusb_dev = NULL; // force a re-scan
246 LEVEL_CONNECT("<%s> Release interface (USB) failed", libusb_error_name(ret));
247 }
248 ret =libusb_attach_kernel_driver( usb,0 ) ;
249 if ( ret != 0 ) {
250 LEVEL_DEBUG("<%s> Linux kernel driver reattach problem",libusb_error_name(ret)) ;
251 }
252
253 libusb_close(usb);
254 in->master.usb.lusb_handle = NULL ;
255 LEVEL_CONNECT("Closed USB DS9490 bus master at %s", DEVICENAME(in));
256 }
257 in->master.usb.lusb_dev = NULL;
258 SAFEFREE(DEVICENAME(in)) ;
259 DEVICENAME(in) = owstrdup(badUSBname);
260 }
261
262 /* ------------------------------------------------------------ */
263 /* --- USB read and write --------------------------------------*/
264
265 // libusb version
DS9490_read(BYTE * buf,size_t size,const struct parsedname * pn)266 SIZE_OR_ERROR DS9490_read(BYTE * buf, size_t size, const struct parsedname *pn)
267 {
268 int ret;
269 int transferred ;
270 struct connection_in * in = pn->selected_connection ;
271
272 ret = usb_transfer( libusb_bulk_transfer, DS2490_EP3, buf, size, &transferred, in ) ;
273 if ( ret == 0 ) {
274 TrafficIn("read",buf,size,pn->selected_connection) ;
275 return transferred;
276 }
277
278 LEVEL_DATA("<%s> Failed DS9490 read", libusb_error_name(ret));
279 STAT_ADD1_BUS(e_bus_read_errors, in);
280 return ret;
281 }
282
283 /* Fills the EP2 buffer in the USB adapter
284 returns number of bytes (size)
285 or <0 for an error */
286 // libusb version
DS9490_write(BYTE * buf,size_t size,const struct parsedname * pn)287 SIZE_OR_ERROR DS9490_write(BYTE * buf, size_t size, const struct parsedname *pn)
288 {
289 int ret;
290 int transferred ;
291 struct connection_in * in = pn->selected_connection ;
292
293 if (size == 0) {
294 return 0;
295 }
296
297 // usb library doesn't require a const data type for writing
298 ret = usb_transfer( libusb_bulk_transfer, DS2490_EP2, buf, size, &transferred, in ) ;
299 TrafficOut("write",buf,size,pn->selected_connection);
300 if ( ret != 0 ) {
301 LEVEL_DATA("<%s> Failed DS9490 write", libusb_error_name(ret));
302 STAT_ADD1_BUS(e_bus_write_errors, in);
303 return ret ;
304 }
305 return transferred ;
306 }
307
308 // Notes from Michael Markstaller:
309 /*
310 Datasheet DS2490 page 29 table 16
311 0: Enable Flags: SPUE=1(bit0) If set to 1, the strong pullup to 5V is enabled, if set to 0, it is disabled.
312 bit1 should be 0 but is 1 ?! SPCE = 4(bit2) If set to 1, a dynamic 1-Wire bus speed change through a Communication command is enabled, if set to 0, it is disabled.
313 1: 1-Wire Speed
314 2: Strong Pullup Duration
315 3: (Reserved)
316 4: Pulldown Slew Rate
317 5: Write-1 Low Time
318 6: Data Sample Offset / Write-0 Recovery Time
319 7: reserved
320 8: Device Status Flags: bit0: SPUA if set to 1, the strong pullup to 5V is currently active, if set to 0, it is inactive.
321 bit3(8): PMOD if set to 1, the DS2490 is powered from USB and external sources, if set to 0, all DS2490 power is provided from USB. FIXME: expose this to clients to check!
322 bit4(16): HALT if set to 1, the DS2490 is currently halted, if set to 0, the device is not halted.
323 bit5(32): IDLE if set to 1, the DS2490 is currently idle, if set to 0, the device is not idle.
324 bit5(64): EPOF: Endpoint 0 FIFO status, see: If EP0F is set to 1, the Endpoint 0 FIFO was full when a new control transfer setup packet was
325 received. This is an error condition in that the setup packet received is discarded due to the full
326 condition. To recover from this state the USB host must send a CTL_RESET_DEVICE command; the
327 device will also recover with a power on reset cycle. Note that the DS2490 will accept and process a
328 CTL_RESET_DEVICE command if the EP0F = 1 state occurs. If EP0F = 0, no FIFO error condition exists.
329 9: Communication Command, Byte 1
330 10: Communication Command, Byte 2
331 11: Communication Command Buffer Status
332 12: 1-Wire Data Out Buffer Status
333 13: 1-Wire Data In Buffer Status
334 */
335
usb_transfer(int (* transfer_function)(struct libusb_device_handle * dev_handle,unsigned char endpoint,BYTE * data,int length,int * transferred,unsigned int timeout),unsigned char endpoint,BYTE * data,int length,int * transferred_return,struct connection_in * in)336 static int usb_transfer( int (*transfer_function) (struct libusb_device_handle *dev_handle, unsigned char endpoint, BYTE *data, int length, int *transferred, unsigned int timeout), unsigned char endpoint, BYTE * data, int length, int * transferred_return, struct connection_in * in )
337 {
338 libusb_device_handle *usb = in->master.usb.lusb_handle;
339 int timeout = in->master.usb.timeout ;
340 int libusb_err ;
341
342 transferred_return[0] = 0 ;
343 do {
344 int transferred ;
345 int ret = transfer_function(usb, endpoint, data, length, &transferred, timeout) ;
346
347 switch (ret ) {
348 case 0:
349 transferred_return[0] += transferred ;
350 return 0 ;
351 case LIBUSB_ERROR_TIMEOUT:
352 if ( transferred == 0 ) {
353 // timeout with no data
354 if ( (libusb_err=libusb_clear_halt( usb, endpoint )) != 0 ) {
355 LEVEL_DEBUG("Synchronous IO error %s",libusb_error_name(libusb_err)) ;
356 }
357 return ret ;
358 }
359 // partial transfer
360 transferred_return[0] += transferred ;
361 length -= transferred ; // decrease remaining length
362 data += transferred ; // move pointer
363 break ;
364 default:
365 // error
366 if ( (libusb_err=libusb_clear_halt( usb, endpoint )) != 0 ) {
367 LEVEL_DEBUG("<%s> Synchronous IO error", libusb_error_name(libusb_err)) ;
368 }
369 return ret ;
370 }
371 } while (1) ;
372 }
373
DS9490_port_setup(libusb_device * dev,struct port_in * pin)374 void DS9490_port_setup( libusb_device * dev, struct port_in * pin )
375 {
376 struct connection_in * in = pin->first ;
377
378 in->master.usb.lusb_handle = NULL ;
379 in->master.usb.lusb_dev = dev ;
380 pin->type = ct_usb ;
381 pin->busmode = bus_usb;
382
383 in->flex = 1 ; // Michael Markstaller suggests this
384 in->Adapter = adapter_DS9490; /* OWFS assigned value */
385 in->adapter_name = "DS9490";
386 memset( in->master.usb.ds1420_address, 0, SERIAL_NUMBER_SIZE ) ;
387
388 SAFEFREE(DEVICENAME(in)) ;
389
390 if ( dev == NULL ) {
391 in->master.usb.address = -1 ;
392 in->master.usb.bus_number = -1 ;
393 DEVICENAME(in) = owstrdup("") ;
394 } else {
395 size_t len = 32 ;
396 int sn_ret ;
397
398 in->master.usb.address = libusb_get_device_address( dev ) ;
399 in->master.usb.bus_number = libusb_get_bus_number( dev ) ;
400
401 DEVICENAME(in) = owmalloc( len+1 ) ;
402 if ( DEVICENAME(in) == NULL ) {
403 return ;
404 }
405
406 UCLIBCLOCK ;
407 sn_ret = snprintf(DEVICENAME(in), len, "%.d:%.d", in->master.usb.bus_number, in->master.usb.address) ;
408 UCLIBCUNLOCK ;
409
410 if (sn_ret <= 0) {
411 DEVICENAME(in)[0] = '\0' ;
412 }
413 }
414 }
415
416 #endif /* OW_USB */
417
418