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 /* This is the busmaster code for the DS1WM
12  * The "Synthesizable 1-wire Bus MAster" adapter from Dallas Maxim
13  *
14  * Out technique is a little dangerous -- direct memory access to the registers
15  * We use /dev/mem although writing a UIO kernel module is also a possibility
16  * Obviously we'll nee root access
17  *
18  */
19 
20  /* Based on a device used by Kistler Corporation
21   * and tested in-house by Martin Rapavy
22   *
23   * That testing also covers the DS1WM
24   * */
25 
26 #include <config.h>
27 #include "owfs_config.h"
28 #include "ow.h"
29 #include "ow_counters.h"
30 #include "ow_connection.h"
31 #include "ow_global.h"
32 #include <sys/mman.h>
33 
34 // DS1WM Registers
35 #define DS1WM_COMMAND_REGISTER 0
36 #define DS1WM_TXRX_BUFFER 1
37 #define DS1WM_INTERRUPT_REGISTER 2
38 #define DS1WM_INTERRUPT_ENABLE_REGISTER 3
39 #define DS1WM_CLOCK_DEVISOR_REGISTER 4
40 #define K1WM_CHANNEL_SELECT_REGISTER DS1WM_CLOCK_DEVISOR_REGISTER
41 #define DS1WM_CONTROL_REGISTER 5
42 
43 // Access register via mmap-ed memory
44 #define DS1WM_register(in, off) (((uint8_t *) (in->master.ds1wm.mm))[(in->master.ds1wm.base)+off])
45 
46 // Register access macros
47 #define DS1WM_command(in)	DS1WM_register(in,DS1WM_COMMAND_REGISTER)
48 #define DS1WM_txrx(in)		DS1WM_register(in,DS1WM_TXRX_BUFFER)
49 #define DS1WM_interrupt(in)	DS1WM_register(in,DS1WM_INTERRUPT_REGISTER)
50 #define DS1WM_enable(in)	DS1WM_register(in,DS1WM_INTERRUPT_ENABLE_REGISTER)
51 #define DS1WM_clock(in)		DS1WM_register(in,DS1WM_CLOCK_DEVISOR_REGISTER)
52 #define K1WM_channel(in)	DS1WM_register(in,K1WM_CHANNEL_SELECT_REGISTER)
53 #define DS1WM_control(in)	DS1WM_register(in,DS1WM_CONTROL_REGISTER)
54 
55 enum e_DS1WM_command { e_ds1wm_1wr=0, e_ds1wm_sra, e_ds1wm_fow, e_ds1wm_ow_in, } ;
56 
57 enum e_DS1WM_int { e_ds1wm_pd=0, e_ds1wm_pdr, e_ds1wm_tbe, e_ds1wm_temt, e_ds1wm_rbf, e_ds1wm_rsrf, e_ds1wm_ow_short, e_ds1wm_ow_low,  } ;
58 
59 enum e_DS1WM_enable { e_ds1wm_epd=0, e_ds1wm_ias, e_ds1wm_etbe, e_ds1wm_etmt, e_ds1wm_erbf, e_ds1wm_ersf, e_ds1wm_eowsh, e_ds1wm_eowl } ;
60 
61 enum e_DS1WM_control { e_ds1wm_llm=0, e_ds1wm_ppm, e_ds1wm_en_fow, e_ds1wm_stpen, e_ds1wm_stp_sply, e_ds1wm_bit_ctl, e_ds1wm_od } ;
62 
63 static RESET_TYPE K1WM_reset(const struct parsedname *pn);
64 static enum search_status K1WM_next_both(struct device_search *ds, const struct parsedname *pn);
65 static GOOD_OR_BAD K1WM_sendback_data(const BYTE * data, BYTE * resp, const size_t len, const struct parsedname *pn);
66 static GOOD_OR_BAD K1WM_reconnect(const struct parsedname * pn);
67 static void K1WM_close(struct connection_in *in) ;
68 
69 static void K1WM_setroutines(struct connection_in *in);
70 
71 static GOOD_OR_BAD K1WM_setup( struct connection_in * in );
72 static RESET_TYPE K1WM_wait_for_reset( struct connection_in * in );
73 static GOOD_OR_BAD K1WM_wait_for_read( const struct connection_in * in );
74 static GOOD_OR_BAD K1WM_wait_for_write( const struct connection_in * in );
75 static GOOD_OR_BAD K1WM_wait_for_byte( const struct connection_in * in );
76 static GOOD_OR_BAD K1WM_sendback_byte(const BYTE * data, BYTE * resp, const struct connection_in * in ) ;
77 
78 static GOOD_OR_BAD read_device_map_offset(const char *device_name, off_t *offset);
79 static GOOD_OR_BAD read_device_map_size(const char *device_name, size_t *size);
80 static GOOD_OR_BAD K1WM_select_channel(const struct connection_in * in, uint8_t channel);
81 static GOOD_OR_BAD K1WM_create_channels(struct connection_in *head, int channels_count);
82 
K1WM_setroutines(struct connection_in * in)83 static void K1WM_setroutines(struct connection_in *in)
84 {
85 	in->iroutines.detect = K1WM_detect;
86 	in->iroutines.reset = K1WM_reset;
87 	in->iroutines.next_both = K1WM_next_both;
88 	// K1WM doesn't have strong pull-up support
89 	in->iroutines.PowerByte = NO_POWERBYTE_ROUTINE;
90 	in->iroutines.PowerBit = NO_POWERBIT_ROUTINE;
91 	in->iroutines.sendback_bits = NO_SENDBACKBITS_ROUTINE;
92 	in->iroutines.ProgramPulse = NO_PROGRAMPULSE_ROUTINE;
93 	in->iroutines.sendback_data = K1WM_sendback_data;
94 	in->iroutines.select = NO_SELECT_ROUTINE;
95 	in->iroutines.select_and_sendback = NO_SELECTANDSENDBACK_ROUTINE;
96 	in->iroutines.set_config = NO_SET_CONFIG_ROUTINE;
97 	in->iroutines.get_config = NO_GET_CONFIG_ROUTINE;
98 	in->iroutines.reconnect = K1WM_reconnect ;
99 	in->iroutines.close = K1WM_close;
100 	in->iroutines.verify = NO_VERIFY_ROUTINE ;
101 	in->iroutines.flags = ADAP_FLAG_default;
102 	in->bundling_length = UART_FIFO_SIZE;
103 }
104 
105 // Search defines
106 #define SEARCH_BIT_ON		0x01
107 
108 /* Setup DS1WM bus master structure */
109 // bus locking at a higher level
K1WM_detect(struct port_in * pin)110 GOOD_OR_BAD K1WM_detect(struct port_in *pin)
111 {
112 	struct connection_in * in = pin->first ;
113 	long long int prebase ;
114 	unsigned int prechannels_count;
115 	void * mm ;
116 	FILE_DESCRIPTOR_OR_ERROR mem_fd ;
117 	const char * mem_device = "/dev/uio0";
118 
119 	if (pin->init_data == NULL) {
120 		LEVEL_DEFAULT("K1WM needs a memory location");
121 		return gbBAD;
122 	}
123 
124 	in->Adapter = adapter_k1wm ;
125 	in->master.ds1wm.longline = 0 ; // longline timing
126 	// in->master.ds1wm.frequency = 0 ; // unused in k1wm
127 	in->master.ds1wm.presence_mask = 1 ; // pulse presence mask
128 	in->master.ds1wm.active_channel = 0;
129 	in->master.ds1wm.channels_count = 1;
130 
131 	int param_count = sscanf( pin->init_data, "%lli,%u", &prebase, &prechannels_count);
132 	if ( param_count < 1 || param_count > 2) {
133 		LEVEL_DEFAULT("K1WM: Could not interpret <%s> as a memory address:channel_count pair", pin->init_data ) ;
134 		return gbBAD ;
135 	}
136 
137 	in->master.ds1wm.channels_count = prechannels_count ;
138 	in->master.ds1wm.base = prebase ; // convert types long long int -> off_t
139 	if ( in->master.ds1wm.base == 0 ) {
140 		LEVEL_DEFAULT("K1WM: Illegal address 0x0000 from <%s>", pin->init_data ) ;
141 		return gbBAD ;
142 	}
143 	LEVEL_DEBUG("K1WM at address %p",(void *)in->master.ds1wm.base);
144 	LEVEL_DEBUG("K1WM channels: %u",in->master.ds1wm.channels_count);
145 
146 	read_device_map_size(mem_device, &(in->master.ds1wm.mm_size));
147 	read_device_map_offset(mem_device, &(in->master.ds1wm.page_start));
148 
149 	// open /dev/uio0
150 	mem_fd = open( mem_device, O_RDWR | O_SYNC ) ;
151 
152 	if ( FILE_DESCRIPTOR_NOT_VALID(mem_fd) ) {
153 		LEVEL_DEFAULT("K1WM: Cannot open memory directly -- permissions problem?");
154 		return gbBAD ;
155 	}
156 
157 	mm = mmap( NULL, in->master.ds1wm.mm_size, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, in->master.ds1wm.page_start );
158 
159 	close(mem_fd) ; // no longer needed
160 
161 	if ( mm == MAP_FAILED ) {
162 		LEVEL_DEFAULT("K1WM: Cannot map memory") ;
163 		return gbBAD ;
164 	}
165 
166 	in->master.ds1wm.mm = mm ;
167 
168 	/* Set up low-level routines */
169 	K1WM_setroutines(in);
170 
171 	// Add channels
172 	K1WM_create_channels(in, in->master.ds1wm.channels_count);
173 
174 	return K1WM_setup(in) ;
175 }
176 
177 // set control pins and frequency for defauts and global settings
K1WM_setup(struct connection_in * in)178 static GOOD_OR_BAD K1WM_setup( struct connection_in * in )
179 {
180 	uint8_t control_register = DS1WM_control(in) ;
181 	LEVEL_DEBUG("[%s] control_register before setup: 0x%x", __FUNCTION__, control_register);
182 
183 	// Set to channel
184 	K1WM_channel(in) = in->master.ds1wm.active_channel ;
185 
186 	// set some defaults:
187 	UT_setbit( &control_register, e_ds1wm_ppm, in->master.ds1wm.presence_mask ) ; // pulse presence masked
188 	UT_setbit( &control_register, e_ds1wm_en_fow, 0 ) ; // no bit banging
189 
190 	UT_setbit( &control_register, e_ds1wm_stpen, 0 ) ; // strong pullup not supported in K1WM
191 	UT_setbit( &control_register, e_ds1wm_stp_sply, 0 ) ; // not in strong pullup state, too
192 
193 	in->master.ds1wm.byte_mode = 1 ; // default
194 	UT_setbit( &control_register, e_ds1wm_bit_ctl, 0 ) ; // byte mode
195 
196 	UT_setbit( &control_register, e_ds1wm_od, in->overdrive ) ; // not overdrive
197 	UT_setbit( &control_register, e_ds1wm_llm, in->master.ds1wm.longline ) ; // set long line flag
198 	DS1WM_control(in) = control_register ;
199 	LEVEL_DEBUG("[%s] control_register after setup: 0x%x", __FUNCTION__, DS1WM_control(in));
200 
201 	if ( DS1WM_control(in) != control_register ) {
202 		return gbBAD ;
203 	}
204 
205 	return gbGOOD ;
206 }
207 
K1WM_reconnect(const struct parsedname * pn)208 static GOOD_OR_BAD K1WM_reconnect(const struct parsedname * pn)
209 {
210 	LEVEL_DEBUG("Attempting reconnect on %s",SAFESTRING(DEVICENAME(pn->selected_connection)));
211 	return K1WM_setup(pn->selected_connection) ;
212 }
213 
214 //--------------------------------------------------------------------------
215 // Reset all of the devices on the 1-Wire Net and return the result.
216 //
217 //          This routine will not function correctly on some
218 //          Alarm reset types of the DS1994/DS1427/DS2404 with
219 //          Rev 1,2, and 3 of the DS2480/DS2480B.
K1WM_reset(const struct parsedname * pn)220 static RESET_TYPE K1WM_reset(const struct parsedname * pn)
221 {
222 	LEVEL_DEBUG("[%s] BUS reset", __FUNCTION__);
223 	struct connection_in * in = pn->selected_connection ;
224 	if ( in->changed_bus_settings != 0) {
225 		in->changed_bus_settings = 0 ;
226 		K1WM_setup(in);	// reset paramters
227 	}
228 
229 	// select channel
230 	K1WM_select_channel(in, in->master.ds1wm.active_channel);
231 
232 	// read interrupt register to clear all bits
233 	(void) DS1WM_interrupt(in);
234 
235 	UT_setbit( &DS1WM_command(in), e_ds1wm_1wr, 1 ) ;
236 
237 	switch( K1WM_wait_for_reset(in) ) {
238 		case BUS_RESET_SHORT:
239 			return BUS_RESET_SHORT ;
240 		case BUS_RESET_OK:
241 			return BUS_RESET_OK ;
242 		default:
243 			return K1WM_wait_for_reset(in) ;
244 	}
245 }
246 
247 #define SERIAL_NUMBER_BITS (8*SERIAL_NUMBER_SIZE)
248 /* search = normal and alarm */
K1WM_next_both(struct device_search * ds,const struct parsedname * pn)249 static enum search_status K1WM_next_both(struct device_search *ds, const struct parsedname *pn)
250 {
251 	LEVEL_DEBUG("[%s] BUS search", __FUNCTION__);
252 	int mismatched;
253 	BYTE sn[SERIAL_NUMBER_SIZE];
254 	BYTE bitpairs[SERIAL_NUMBER_SIZE*2];
255 	BYTE dummy ;
256 	struct connection_in * in = pn->selected_connection ;
257 	int i;
258 
259 	LEVEL_DEBUG("[%s] ds->LastDevice == true ?", __FUNCTION__);
260 	if (ds->LastDevice) {
261 		LEVEL_DEBUG("[%s] ds->LastDevice == true -> search_done", __FUNCTION__);
262 		return search_done;
263 	}
264 
265 	LEVEL_DEBUG("[%s] BUS_select failed ?", __FUNCTION__);
266 	if ( BAD( BUS_select(pn) ) ) {
267 		LEVEL_DEBUG("[%s] BUS_select failed -> search_error", __FUNCTION__);
268 		return search_error;
269 	}
270 
271 	// Standard SEARCH ROM using SRA
272 	// need the reset done in BUS-select to set AnyDevices
273 	if ( in->AnyDevices == anydevices_no ) {
274 		LEVEL_DEBUG("[%s] in->AnyDevices == anydevices_no -> search_done", __FUNCTION__);
275 		ds->LastDevice = 1;
276 		return search_done;
277 	}
278 
279 	// clear sn to satisfy static error checking (Coverity)
280 	memset( sn, 0, SERIAL_NUMBER_SIZE ) ;
281 
282 	// build the command stream
283 	// call a function that may add the change mode command to the buff
284 	// check if correct mode
285 	// issue the search command
286 	// change back to command mode
287 	// search mode on
288 	// change back to data mode
289 
290 	// set the temp Last Descrep to none
291 	mismatched = -1;
292 
293 	// add the 16 bytes of the search
294 	memset(bitpairs, 0, SERIAL_NUMBER_SIZE*2);
295 
296 	LEVEL_DEBUG("[%s] ds->LastDiscrepancy == %i", __FUNCTION__, ds->LastDiscrepancy);
297 	// set the bits in the added buffer
298 	for (i = 0; i < ds->LastDiscrepancy; i++) {
299 		// before last discrepancy
300 		UT_set2bit(bitpairs, i, UT_getbit(ds->sn, i) << 1);
301 	}
302 	// at last discrepancy
303 	if (ds->LastDiscrepancy > -1) {
304 		UT_set2bit(bitpairs, ds->LastDiscrepancy, 1 << 1);
305 	}
306 	// after last discrepancy so leave zeros
307 
308 	// search ON
309 	// Send search rom or conditional search byte
310 	if ( BAD( K1WM_sendback_byte(&(ds->search), &dummy, in) ) ) {
311 		LEVEL_DEBUG("[%s] Sending SearchROM/SearchByte '0x%x' failed -> search_error", __FUNCTION__, ds->search);
312 		return search_error;
313 	}
314 
315 	// Set search accelerator
316 	UT_setbit( &DS1WM_command(in), e_ds1wm_sra, 1 ) ;
317 
318 	// send the packet
319 	// cannot use single-bit mode with search accerator
320 	// search OFF
321 	if ( BAD( K1WM_sendback_data(bitpairs, bitpairs, SERIAL_NUMBER_SIZE*2, pn) ) ) {
322 		LEVEL_DEBUG("[%s] Sending the packet (bitpairs) failed -> search_error", __FUNCTION__);
323 		return search_error;
324 	}
325 
326 	// Turn off search accelerator
327 	UT_setbit( &DS1WM_command(in), e_ds1wm_sra, 0 ) ;
328 
329 	// interpret the bit stream
330 	for (i = 0; i < SERIAL_NUMBER_BITS; i++) {
331 		// get the SerialNum bit
332 		UT_setbit(sn, i, UT_get2bit(bitpairs, i) >> 1);
333 		// check LastDiscrepancy
334 		if (UT_get2bit(bitpairs, i) == SEARCH_BIT_ON ) {
335 			mismatched = i;
336 		}
337 	}
338 
339 	if ( sn[0]==0xFF && sn[1]==0xFF && sn[2]==0xFF && sn[3]==0xFF && sn[4]==0xFF && sn[5]==0xFF && sn[6]==0xFF && sn[7]==0xFF ) {
340 		// special case for no alarm present
341 		LEVEL_DEBUG("[%s] sn == 0xFFFFFFFFFFFFFFFF -> search_error", __FUNCTION__);
342 		return search_done ;
343 	}
344 
345 	// CRC check
346 	if (CRC8(sn, SERIAL_NUMBER_SIZE) || (ds->LastDiscrepancy == SERIAL_NUMBER_BITS-1) || (sn[0] == 0)) {
347 		LEVEL_DEBUG("[%s] CRC check failed -> search_error", __FUNCTION__);
348 		return search_error;
349 	}
350 
351 	// successful search
352 	// check for last one
353 	if ((mismatched == ds->LastDiscrepancy) || (mismatched == -1)) {
354 		ds->LastDevice = 1;
355 	}
356 
357 	// copy the SerialNum to the buffer
358 	memcpy(ds->sn, sn, 8);
359 
360 	// set the count
361 	ds->LastDiscrepancy = mismatched;
362 
363 	LEVEL_DEBUG("SN found: " SNformat, SNvar(ds->sn));
364 	return search_good;
365 }
366 
K1WM_sendback_byte(const BYTE * data,BYTE * resp,const struct connection_in * in)367 static GOOD_OR_BAD K1WM_sendback_byte(const BYTE * data, BYTE * resp, const struct connection_in * in )
368 {
369 	LEVEL_DEBUG("[%s] sending byte: 0x%x", __FUNCTION__, data[0]);
370 	RETURN_BAD_IF_BAD( K1WM_wait_for_write(in) ) ;
371 	DS1WM_txrx(in) = data[0] ;
372 	RETURN_BAD_IF_BAD( K1WM_wait_for_read(in) ) ;
373 	resp[0] = DS1WM_txrx(in) ;
374 	LEVEL_DEBUG("[%s] received byte: 0x%x", __FUNCTION__, resp[0]);
375 	return gbGOOD ;
376 }
377 
378 //
379 // sendback_data
380 //  Send data and return response block
K1WM_sendback_data(const BYTE * data,BYTE * resp,const size_t len,const struct parsedname * pn)381 static GOOD_OR_BAD K1WM_sendback_data(const BYTE * data, BYTE * resp, const size_t len, const struct parsedname *pn)
382 {
383 	LEVEL_DEBUG("[%s]", __FUNCTION__);
384 	struct connection_in * in = pn->selected_connection ;
385 	size_t i ;
386 
387 	K1WM_select_channel(in, in->master.ds1wm.active_channel);
388 
389 	for (i=0 ; i<len ; ++i ) {
390 		RETURN_BAD_IF_BAD( K1WM_sendback_byte( data+i, resp+i, in ) ) ;
391 	}
392 
393 	return gbGOOD ;
394 }
395 
K1WM_close(struct connection_in * in)396 static void K1WM_close(struct connection_in *in)
397 {
398 	LEVEL_DEBUG("[%s] Closing BUS", __FUNCTION__);
399 	// the standard COM_free cleans up the connection
400 	munmap( in->master.ds1wm.mm, in->master.ds1wm.mm_size );
401 }
402 
403 // wait for reset
K1WM_wait_for_byte(const struct connection_in * in)404 static GOOD_OR_BAD K1WM_wait_for_byte( const struct connection_in * in )
405 {
406 	int bits = in->master.ds1wm.byte_mode ? 8 : 1 ;
407 	long int t_slot = in->overdrive ? 15000 : 86000 ; // nsec
408 	struct timespec t = {
409 		0,
410 		t_slot*bits,
411 	};
412 
413 	if ( nanosleep( & t, NULL ) != 0 ) {
414 		return gbBAD ;
415 	}
416 	return gbGOOD ;
417 }
418 
419 // Wait max time needed for reset
K1WM_wait_for_reset(struct connection_in * in)420 static RESET_TYPE K1WM_wait_for_reset( struct connection_in * in )
421 {
422 	LEVEL_DEBUG("[%s]", __FUNCTION__);
423 	long int t_reset = in->overdrive ? (74000+63000) : (636000+626000) ; // nsec
424 	uint8_t interrupt ;
425 	struct timespec t = {
426 		0,
427 		t_reset,
428 	} ;
429 
430 	if ( nanosleep( & t, NULL ) != 0 ) {
431 		return gbBAD ;
432 	}
433 
434 	interrupt = DS1WM_interrupt(in) ;
435 	if ( UT_getbit( &interrupt, e_ds1wm_pd ) == 0 ) {
436 		LEVEL_DEBUG("[%s] presence_detect bit == 0", __FUNCTION__);
437 		return BUS_RESET_ERROR ;
438 	}
439 	if ( UT_getbit( &interrupt, e_ds1wm_ow_short ) == 1 ) {
440 		LEVEL_DEBUG("[%s] short bit == 1", __FUNCTION__);
441 		return BUS_RESET_SHORT ;
442 	}
443 
444 	in->AnyDevices = ( UT_getbit( &interrupt, e_ds1wm_pdr ) == 0 ) ? anydevices_yes : anydevices_no ;
445 	LEVEL_DEBUG("[%s] in->AnyDevices == %i", __FUNCTION__, in->AnyDevices);
446 	return BUS_RESET_OK ;
447 }
448 
K1WM_wait_for_read(const struct connection_in * in)449 static GOOD_OR_BAD K1WM_wait_for_read( const struct connection_in * in )
450 {
451 	int i ;
452 
453 	if ( UT_getbit( &DS1WM_interrupt(in), e_ds1wm_rbf ) == 1 ) {
454 		return gbGOOD ;
455 	}
456 
457 	for ( i=0 ; i < 5 ; ++i ) {
458 		RETURN_BAD_IF_BAD( K1WM_wait_for_byte(in) ) ;
459 		if ( UT_getbit( &DS1WM_interrupt(in), e_ds1wm_rbf ) == 1 ) {
460 			return gbGOOD ;
461 		}
462 	}
463 	return gbBAD ;
464 }
465 
K1WM_wait_for_write(const struct connection_in * in)466 static GOOD_OR_BAD K1WM_wait_for_write( const struct connection_in * in )
467 {
468 	int i ;
469 
470 	if ( UT_getbit( &DS1WM_interrupt(in), e_ds1wm_tbe ) == 1 ) {
471 		return gbGOOD ;
472 	}
473 
474 	for ( i=0 ; i < 5 ; ++i ) {
475 		RETURN_BAD_IF_BAD( K1WM_wait_for_byte(in) ) ;
476 		if ( UT_getbit( &DS1WM_interrupt(in), e_ds1wm_tbe ) == 1 ) {
477 			return gbGOOD ;
478 		}
479 	}
480 	return gbBAD ;
481 }
482 
read_device_map_offset(const char * device_name,off_t * offset)483 static GOOD_OR_BAD read_device_map_offset(const char *device_name, off_t *offset)
484 {
485 	const unsigned char path_length = 100;
486 	FILE* file;
487 	unsigned int preoffset;
488 
489 	// Get device filename (e.g. uio0)
490 	const char *uio_filename = strrchr(device_name, '/');
491 	if (uio_filename == NULL) {
492 		return gbBAD;
493 	}
494 
495 	// Offset parameter file path
496 	char uio_map_offset_file[path_length];
497 	snprintf(uio_map_offset_file, path_length, "/sys/class/uio/%s/maps/map0/offset", uio_filename);
498 
499 	// Read offset parameter
500 	file = fopen(uio_map_offset_file, "r");
501 	if (file == NULL) {
502 		return gbBAD;
503 	}
504 	if (fscanf(file, "%x", &preoffset) != 1) {
505 		fclose(file);
506 		return gbBAD;
507 	}
508 	fclose(file);
509 	*offset = preoffset;
510 	LEVEL_DEBUG("[%s] map offset: 0x%x", __FUNCTION__, preoffset);
511 	LEVEL_DEBUG("[%s] map offset: 0x%x", __FUNCTION__, *offset);
512 
513 	return gbGOOD;
514 }
515 
read_device_map_size(const char * device_name,size_t * size)516 static GOOD_OR_BAD read_device_map_size(const char *device_name, size_t *size)
517 {
518 	const unsigned char path_length = 100;
519 	unsigned int usize ;
520 	FILE* file;
521 
522 	// Get device filename (e.g. uio0)
523 	const char *uio_filename = strrchr(device_name, '/');
524 	if (uio_filename == NULL) {
525 		return gbBAD;
526 	}
527 
528 	// Size parameter file path
529 	char uio_map_size_file[path_length];
530 	snprintf(uio_map_size_file, path_length, "/sys/class/uio/%s/maps/map0/size", uio_filename);
531 
532 	// Read size parameter
533 	file = fopen(uio_map_size_file, "r");
534 	if (file == NULL) {
535 		return gbBAD;
536 	}
537 	if (fscanf(file, "%x", &usize) != 1){
538 		fclose(file);
539 		return gbBAD;
540 	}
541 	*size = usize ;
542 	fclose(file);
543 	LEVEL_DEBUG("[%s] map size: 0x%x", __FUNCTION__, *size);
544 
545 	return gbGOOD;
546 }
547 
K1WM_select_channel(const struct connection_in * in,uint8_t channel)548 static GOOD_OR_BAD K1WM_select_channel(const struct connection_in * in, uint8_t channel)
549 {
550 	LEVEL_DEBUG("[%s] Selecting channel %u", __FUNCTION__, channel);
551 
552 	// in K1WM clock register is used as output multiplexer register
553 	K1WM_channel(in) = channel;
554 	return K1WM_channel(in) == channel ? gbGOOD : gbBAD;
555 }
556 
K1WM_create_channels(struct connection_in * head,int channels_count)557 static GOOD_OR_BAD K1WM_create_channels(struct connection_in *head, int channels_count)
558 {
559 	int i;
560 
561 	static char *channel_names[] = {
562 		"K1WM(0)", "K1WM(1)", "K1WM(2)", "K1WM(3)", "K1WM(4)", "K1WM(5)", "K1WM(6)", "K1WM(7)",
563 		"K1WM(8)", "K1WM(9)", "K1WM(10)", "K1WM(11)", "K1WM(12)", "K1WM(13)", "K1WM(14)", "K1WM(15)",
564 		"K1WM(16)", "K1WM(17)", "K1WM(18)", "K1WM(19)", "K1WM(20)", "K1WM(21)", "K1WM(22)", "K1WM(23)",
565 		"K1WM(24)", "K1WM(25)", "K1WM(26)", "K1WM(27)", "K1WM(28)", "K1WM(29)", "K1WM(30)", "K1WM(31)",
566 		"K1WM(32)", "K1WM(33)", "K1WM(34)", "K1WM(35)", "K1WM(36)", "K1WM(37)", "K1WM(38)", "K1WM(39)",
567 		"K1WM(40)", "K1WM(41)", "K1WM(42)", "K1WM(43)", "K1WM(44)", "K1WM(45)", "K1WM(46)", "K1WM(47)",
568 		"K1WM(48)", "K1WM(49)", "K1WM(50)", "K1WM(51)", "K1WM(52)", "K1WM(53)", "K1WM(54)", "K1WM(55)",
569 		"K1WM(56)", "K1WM(57)", "K1WM(58)", "K1WM(59)", "K1WM(60)", "K1WM(61)", "K1WM(62)", "K1WM(63)"
570 	};
571 	head->master.ds1wm.active_channel = 0;
572 	head->adapter_name = channel_names[0] ;
573 	for (i = 1; i < channels_count; ++i) {
574 		struct connection_in * added = AddtoPort(head->pown);
575 		if (added == NO_CONNECTION) {
576 			return gbBAD;
577 		}
578 		added->master.ds1wm.active_channel = i;
579 		added->adapter_name = channel_names[i] ;
580 	}
581 	return gbGOOD;
582 }
583 
584