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