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