libpruio  0.6.8
Fast and easy Digital/Analog Input/Output for Beaglebones
pruio_prussdrv.bas
Go to the documentation of this file.
1 
19 
20 ' Basic header
21 #INCLUDE ONCE "dir.bi"
22 ' The header for kernel drivercode.
23 #INCLUDE ONCE "pruio_prussdrv.bi"
24 ' Header file with pin arrays.
25 #INCLUDE ONCE "pruio_boardpins.bi"
26 
27 
28 
29 DIM SHARED AS tprussdrv PRUSSDRV
30 
31 
32 #DEFINE PAGE_SIZE 4096
33 
34 ' PRUSS INTC register offsets
35 
36 #DEFINE PRU_INTC_GER_REG &h010
37 
38 #DEFINE PRU_INTC_HIEISR_REG &h034
39 
40 #DEFINE PRU_INTC_SRSR0_REG &h200
41 
42 #DEFINE PRU_INTC_SRSR1_REG &h204
43 
44 #DEFINE PRU_INTC_SECR0_REG &h280
45 
46 #DEFINE PRU_INTC_SECR1_REG &h284
47 
48 #DEFINE PRU_INTC_ESR0_REG &h300
49 
50 #DEFINE PRU_INTC_ESR1_REG &h304
51 
52 #DEFINE PRU_INTC_CMR0_REG &h400
53 
54 #DEFINE PRU_INTC_HMR0_REG &h800
55 
56 #DEFINE PRU_INTC_SIPR0_REG &hD00
57 
58 #DEFINE PRU_INTC_SIPR1_REG &hD04
59 
60 #DEFINE PRU_INTC_SITR0_REG &hD80
61 
62 #DEFINE PRU_INTC_SITR1_REG &hD84
63 
64 
65 #DEFINE MAX_HOSTS_SUPPORTED 10
66 
67 
68 #DEFINE PRUSS_UIO_PARAM_VAL_LEN 20
69 
70 #DEFINE KERNEL_PINMUX_PINS "/sys/kernel/debug/pinctrl/44e10800.pinmux/pinmux-pins"
71 
72 #DEFINE KERNEL_PINMUX_PINX "/sys/kernel/debug/pinctrl/44e10800.pinmux-pinctrl-single/pinmux-pins"
73 
74 '#include once "crt/fcntl.bi" ' from: bits/fnctl-linux.h
75 
76 TYPE AS UInt32 size_t
77 
78 TYPE AS Int32 ssize_t
79 
80 
81 #DEFINE O_ACCMODE &o003
82 
83 #DEFINE O_RDONLY &o0
84 
85 #DEFINE O_WRONLY &o1
86 
87 #DEFINE O_RDWR &o2
88 
89 #DEFINE O_CREAT &o100 ' Not fcntl.
90 
91 #DEFINE O_EXCL &o200 ' Not fcntl.
92 
93 #DEFINE O_NOCTTY &o400 ' Not fcntl.
94 
95 #DEFINE O_TRUNC &o1000 ' Not fcntl.
96 
97 #DEFINE O_APPEND &o2000
98 
99 #DEFINE O_NONBLOCK &o4000
100 
101 #DEFINE O_NDELAY O_NONBLOCK
102 
103 #DEFINE O_SYNC &o4010000
104 
105 ' from: bits/mman-linux.h
106 
107 #DEFINE PROT_READ &h1 '
108 
109 #DEFINE PROT_WRITE &h2
110 
111 #DEFINE PROT_EXEC &h4
112 
113 #DEFINE PROT_NONE &h0
114 
115 #DEFINE PROT_GROWSDOWN &h01000000
116 
117 #DEFINE PROT_GROWSUP &h02000000
118 
119 
120 #DEFINE MAP_SHARED &h01
121 
122 #DEFINE MAP_PRIVATE &h02
123 #IFDEF __USE_MISC
124 
125  #DEFINE MAP_TYPE &h0f
126 #ENDIF
127 
128 
129 TYPE AS Int32 off_t
130 
131 TYPE AS ANY PTR addr_t
132 
133 TYPE AS UInt8 PTR caddr_t
134 
135 
136 DECLARE FUNCTION mmap CDECL ALIAS "mmap"(BYVAL AS addr_t, BYVAL AS size_t, BYVAL AS Int32, BYVAL AS Int32, BYVAL AS Int32, BYVAL AS off_t) AS caddr_t
137 
138 DECLARE FUNCTION memcpy CDECL ALIAS "memcpy"(BYVAL AS ANY PTR, BYVAL AS ANY PTR, BYVAL AS size_t) AS ANY PTR
139 
140 DECLARE FUNCTION munmap CDECL ALIAS "munmap"(BYVAL AS ANY PTR, BYVAL AS size_t) AS Int32
141 
142 DECLARE FUNCTION open_ CDECL ALIAS "open"(BYVAL AS CONST ZSTRING PTR, BYVAL AS Int32, ...) AS Int32
143 
144 DECLARE FUNCTION read_ CDECL ALIAS "read"(BYVAL AS Int32, BYVAL AS ANY PTR, BYVAL AS size_t) AS ssize_t
145 
146 DECLARE FUNCTION close_ CDECL ALIAS "close"(BYVAL AS Int32) AS Int32
147 
148 
149 
158 SUB __prussintc_set_cmr CDECL(BYVAL Intc AS UInt32 PTR, BYVAL Event AS UInt16, BYVAL Ch AS UInt16)
159  Intc[(PRU_INTC_CMR0_REG + (Event AND NOT(&b11))) SHR 2] _
160  OR= ((Ch AND &b1111) SHL ((Event AND &b11) SHL 3))
161 END SUB
162 
163 
164 
173 SUB __prussintc_set_hmr CDECL(BYVAL Intc AS UInt32 PTR, BYVAL Ch AS UInt16, BYVAL Host AS UInt16)
174  Intc[(PRU_INTC_HMR0_REG + (Ch AND NOT(&b11))) SHR 2] _
175  = Intc[(PRU_INTC_HMR0_REG + (Ch AND NOT(&b11))) SHR 2] _
176  OR (((Host) AND &b1111) SHL (((Ch) AND &b11) SHL 3))
177 END SUB
178 
179 
180 
189 FUNCTION __prussdrv_memmap_init CDECL(BYVAL IrqFd AS Int32) AS Int32
190  WITH PRUSSDRV
191  DIM AS STRING*PRUSS_UIO_PARAM_VAL_LEN buff = ""
192 
193  VAR fd = open_("/sys/class/uio/uio0/maps/map0/size", O_RDONLY) : IF fd < 0 THEN RETURN -11
194  read_(fd, @buff, PRUSS_UIO_PARAM_VAL_LEN)
195  .pruss_map_size = VALINT("&h" + MID(buff, 3))
196  close_(fd)
197 
198  fd = open_("/sys/class/uio/uio0/maps/map1/addr", O_RDONLY) : IF fd < 0 THEN RETURN -12
199  read_(fd, @buff, PRUSS_UIO_PARAM_VAL_LEN)
200  .extram_phys_base = VALINT("&h" + MID(buff, 3))
201  close_(fd)
202 
203  fd = open_("/sys/class/uio/uio0/maps/map1/size", O_RDONLY) : IF fd < 0 THEN RETURN -13
204  read_(fd, @buff, PRUSS_UIO_PARAM_VAL_LEN)
205  .extram_map_size = VALINT("&h" + MID(buff, 3))
206  close_(fd)
207 
208  .mmap_fd = IrqFd
209 
210  .pru0_dataram_base = mmap( _
211  0, .pruss_map_size, PROT_READ OR PROT_WRITE, _
212  MAP_SHARED, .mmap_fd, 0 * PAGE_SIZE)
213 
214  .pru1_dataram_base = .pru0_dataram_base _
215  + .pru1_dataram_phy_base - .pru0_dataram_phy_base
216  .intc_base = .pru0_dataram_base _
217  + .intc_phy_base - .pru0_dataram_phy_base
218  .pru0_control_base = .pru0_dataram_base _
219  + .pru0_control_phy_base - .pru0_dataram_phy_base
220  .pru1_control_base = .pru0_dataram_base _
221  + .pru1_control_phy_base - .pru0_dataram_phy_base
222  .pru0_iram_base = .pru0_dataram_base _
223  + .pru0_iram_phy_base - .pru0_dataram_phy_base
224  .pru1_iram_base = .pru0_dataram_base _
225  + .pru1_iram_phy_base - .pru0_dataram_phy_base
226  .pruss_sharedram_base = .pru0_dataram_base _
227  + .pruss_sram_phy_base - .pru0_dataram_phy_base
228 
229  .extram_base = mmap( _
230  0, .extram_map_size, PROT_READ OR PROT_WRITE, _
231  MAP_SHARED, .mmap_fd, 1 * PAGE_SIZE)
232  END WITH : RETURN 0
233 END FUNCTION
234 
235 
236 
250 FUNCTION prussdrv_open CDECL ALIAS "prussdrv_open"(BYVAL Irq AS UInt32) AS Int32 EXPORT
251  WITH PRUSSDRV : IF .fd(Irq) THEN RETURN -1 ' already open
252  ' ToDo: find correct /dev/uioX in case of multiple uio drivers
253  VAR nam = "/dev/uio" & HEX(Irq, 1)
254  .fd(Irq) = open_(nam, O_RDWR OR O_SYNC) : IF .fd(Irq) < 0 THEN RETURN -2 ' open failed
255  RETURN IIF(.mmap_fd, 0, __prussdrv_memmap_init(.fd(Irq)))
256  END WITH
257 END FUNCTION
258 
259 
260 
274 FUNCTION prussdrv_pru_enable CDECL ALIAS "prussdrv_pru_enable"(BYVAL PruId AS UInt32, BYVAL PCnt AS UInt32 = 0) AS Int32 EXPORT
275  IF PCnt > &h1FFC THEN RETURN -2
276  DIM AS UInt32 v = (((PCnt + 3) SHR 2) SHL 16) OR 2
277  SELECT CASE AS CONST PruId
278  CASE 0 : *CAST(UInt32 PTR, PRUSSDRV.pru0_control_base) = v : RETURN 0
279  CASE 1 : *CAST(UInt32 PTR, PRUSSDRV.pru1_control_base) = v : RETURN 0
280  END SELECT : RETURN -1
281 END FUNCTION
282 
283 
284 
292 FUNCTION prussdrv_pru_disable CDECL ALIAS "prussdrv_pru_disable"(BYVAL PruId AS UInt32) AS Int32 EXPORT
293  SELECT CASE AS CONST PruId
294  CASE 0 : *CAST(UInt32 PTR, PRUSSDRV.pru0_control_base) = 1 : RETURN 0
295  CASE 1 : *CAST(UInt32 PTR, PRUSSDRV.pru1_control_base) = 1 : RETURN 0
296  END SELECT : RETURN -1
297 END FUNCTION
298 
299 
300 
309 FUNCTION prussdrv_pru_reset CDECL ALIAS "prussdrv_pru_reset"(BYVAL PruId AS UInt32) AS Int32 EXPORT
310  SELECT CASE AS CONST PruId
311  CASE 0 : *CAST(UInt32 PTR, PRUSSDRV.pru0_control_base) = 0 : RETURN 0
312  CASE 1 : *CAST(UInt32 PTR, PRUSSDRV.pru1_control_base) = 0 : RETURN 0
313  END SELECT : RETURN -1
314 END FUNCTION
315 
316 
317 
326 FUNCTION prussdrv_pru_resume CDECL ALIAS "prussdrv_pru_resume"(BYVAL PruId AS UInt32) AS ZSTRING PTR EXPORT
327  DIM AS UInt32 PTR p
328  SELECT CASE AS CONST PruId
329  CASE 0 : p = PRUSSDRV.pru0_control_base
330  CASE 1 : p = PRUSSDRV.pru1_control_base
331  CASE ELSE : RETURN @"invalid PRU#"
332  END SELECT : IF p[0] AND &h8000 /' test bit 15 '/ THEN RETURN @"PRU is running"
333  p[0] = ((1 + p[1]) SHL 16) OR 2 : RETURN 0
334 END FUNCTION
335 
336 
337 
350 FUNCTION prussdrv_pru_write_memory CDECL ALIAS "prussdrv_pru_write_memory"( _
351  BYVAL RamId AS UInt32 _
352 , BYVAL Offs AS UInt32 _
353 , BYVAL Dat AS CONST UInt32 PTR _
354 , BYVAL Size AS UInt32) AS Int32 EXPORT
355 
356  DIM AS UInt32 PTR m
357  SELECT CASE AS CONST RamId
358  CASE PRUSS0_PRU0_DRAM : m = CAST(UInt32 PTR, PRUSSDRV.pru0_dataram_base ) + Offs
359  CASE PRUSS0_PRU1_DRAM : m = CAST(UInt32 PTR, PRUSSDRV.pru1_dataram_base ) + Offs
360  CASE PRUSS0_PRU0_IRAM : m = CAST(UInt32 PTR, PRUSSDRV.pru0_iram_base ) + Offs
361  CASE PRUSS0_PRU1_IRAM : m = CAST(UInt32 PTR, PRUSSDRV.pru1_iram_base ) + Offs
362  CASE PRUSS0_SRAM : m = CAST(UInt32 PTR, PRUSSDRV.pruss_sharedram_base) + Offs
363  CASE ELSE : RETURN -1
364  END SELECT : VAR l = (Size + 3) SHR 2 ' Adjust length as multiple of 4 bytes
365  FOR i AS Int32 = 0 TO l - 1
366  m[i] = Dat[i]
367  NEXT : RETURN l
368 END FUNCTION
369 
370 
371 
385 FUNCTION prussdrv_pruintc_init CDECL ALIAS "prussdrv_pruintc_init"(BYVAL DatIni AS CONST tpruss_intc_initdata PTR) AS Int32 EXPORT
386  WITH PRUSSDRV
387  VAR intc = CAST(UInt32 PTR, .intc_base)
388  DIM AS UInt32 i, mask1, mask2
389 
390  intc[PRU_INTC_SIPR0_REG SHR 2] = &hFFFFFFFFuL
391  intc[PRU_INTC_SIPR1_REG SHR 2] = &hFFFFFFFFuL
392 
393  FOR i = 0 TO ((NUM_PRU_SYS_EVTS + 3) SHR 2) - 1
394  intc[(PRU_INTC_CMR0_REG SHR 2) + i] = 0
395  NEXT
396 
397  i = 0
398  WHILE DatIni->sysevt_to_channel_map(i).sysevt <> -1 ANDALSO _
399  DatIni->sysevt_to_channel_map(i).channel <> -1
400  __prussintc_set_cmr(intc _
401  , DatIni->sysevt_to_channel_map(i).sysevt _
402  , DatIni->sysevt_to_channel_map(i).channel)
403  i += 1
404  WEND
405  FOR i = 0 TO ((NUM_PRU_HOSTS + 3) SHR 2) - 1
406  intc[(PRU_INTC_HMR0_REG SHR 2) + i] = 0
407  NEXT
408 
409  i = 0
410  WHILE (DatIni->channel_to_host_map(i).channel <> -1) ANDALSO _
411  (DatIni->channel_to_host_map(i).host <> -1)
412  __prussintc_set_hmr(intc _
413  , DatIni->channel_to_host_map(i).channel _
414  , DatIni->channel_to_host_map(i).host)
415  i += 1
416  WEND
417 
418  intc[PRU_INTC_SITR0_REG SHR 2] = 0
419  intc[PRU_INTC_SITR1_REG SHR 2] = 0
420 
421  i = 0 : mask1 = 0 : mask2 = 0
422  WHILE DatIni->sysevts_enabled(i) <> -1
423  SELECT CASE DatIni->sysevts_enabled(i)
424  CASE IS < 32 : mask1 = mask1 + (1 SHL (DatIni->sysevts_enabled(i)))
425  CASE IS < 64 : mask2 = mask2 + (1 SHL (DatIni->sysevts_enabled(i) - 32))
426  CASE ELSE : RETURN -1
427  END SELECT : i += 1
428  WEND
429 
430  intc[PRU_INTC_ESR0_REG SHR 2] = mask1
431  intc[PRU_INTC_SECR0_REG SHR 2] = mask1
432  intc[PRU_INTC_ESR1_REG SHR 2] = mask2
433  intc[PRU_INTC_SECR1_REG SHR 2] = mask2
434 
435  FOR i = 0 TO MAX_HOSTS_SUPPORTED - 1
436  IF DatIni->host_enable_bitmask AND (1 SHL i) _
437  THEN intc[PRU_INTC_HIEISR_REG SHR 2] = i
438  NEXT
439 
440  intc[PRU_INTC_GER_REG SHR 2] = &h1
441  memcpy(@.intc_data, CAST(ANY PTR, DatIni), SIZEOF(.intc_data))
442  END WITH : RETURN 0
443 END FUNCTION
444 
445 
446 
454 SUB prussdrv_pru_send_event CDECL ALIAS "prussdrv_pru_send_event"(BYVAL Event AS UInt32) EXPORT
455  VAR intc = CAST(UInt32 PTR, PRUSSDRV.intc_base)
456  IF Event < 32 THEN intc[PRU_INTC_SRSR0_REG SHR 2] = 1 SHL Event _
457  ELSE intc[PRU_INTC_SRSR1_REG SHR 2] = 1 SHL (Event - 32)
458 END SUB
459 
460 
461 
470 FUNCTION prussdrv_pru_wait_event CDECL ALIAS "prussdrv_pru_wait_event"(BYVAL Irq AS UInt32) AS UInt32 EXPORT
471  DIM AS UInt32 event_count
472  read_(PRUSSDRV.fd(Irq), @event_count, SIZEOF(UInt32))
473  RETURN event_count
474 END FUNCTION
475 
476 
477 
487 SUB prussdrv_pru_clear_event CDECL ALIAS "prussdrv_pru_clear_event"(BYVAL Irq AS UInt32, BYVAL Event AS UInt32) EXPORT
488  VAR intc = CAST(UInt32 PTR, PRUSSDRV.intc_base)
489  IF Event < 32 THEN intc[PRU_INTC_SECR0_REG SHR 2] = 1 SHL Event _
490  ELSE intc[PRU_INTC_SECR1_REG SHR 2] = 1 SHL (Event - 32)
491  intc[PRU_INTC_HIEISR_REG SHR 2] = Irq + 2 ' after clear Event!
492 END SUB
493 
494 
495 
503 SUB prussdrv_map_extmem CDECL ALIAS "prussdrv_map_extmem"(BYVAL Addr AS ANY PTR PTR) EXPORT
504  *Addr = PRUSSDRV.extram_base
505 END SUB ' -> property
506 
507 
508 
517 FUNCTION prussdrv_extmem_sIze CDECL ALIAS "prussdrv_extmem_size"() AS UInt32 EXPORT
518  RETURN PRUSSDRV.extram_map_size
519 END FUNCTION ' -> property
520 
521 
522 
535 FUNCTION prussdrv_map_prumem CDECL ALIAS "prussdrv_map_prumem"(BYVAL RamId AS UInt32, BYVAL Addr AS ANY PTR PTR) AS Int32 EXPORT
536  SELECT CASE AS CONST RamId
537  CASE PRUSS0_PRU0_DRAM : *Addr = PRUSSDRV.pru0_dataram_base : RETURN 0
538  CASE PRUSS0_PRU1_DRAM : *Addr = PRUSSDRV.pru1_dataram_base : RETURN 0
539  CASE PRUSS0_PRU0_IRAM : *Addr = PRUSSDRV.pru0_iram_base : RETURN 0
540  CASE PRUSS0_PRU1_IRAM : *Addr = PRUSSDRV.pru1_iram_base : RETURN 0
541  CASE PRUSS0_SRAM : *Addr = PRUSSDRV.pruss_sharedram_base : RETURN 0
542  END SELECT : *Addr = 0 : RETURN -1
543 END FUNCTION
544 
545 
546 
556 FUNCTION prussdrv_get_phys_addr CDECL ALIAS "prussdrv_get_phys_addr"(BYVAL Addr AS CONST ANY PTR) AS UInt32 EXPORT
557  WITH PRUSSDRV
558  SELECT CASE Addr
559  CASE .pru0_dataram_base TO .pru0_dataram_base + .pruss_map_size - 1
560  RETURN CAST(UInt32, Addr - .pru0_dataram_base) + .pru0_dataram_phy_base
561  CASE .extram_base TO .extram_base + .extram_map_size - 1
562  RETURN CAST(UInt32, Addr - .extram_base) + .extram_phys_base
563  END SELECT : RETURN 0
564  END WITH
565 END FUNCTION ' -> property
566 
567 
568 
576 SUB prussdrv_exIt CDECL ALIAS "prussdrv_exit"() EXPORT
577  WITH PRUSSDRV
578  munmap(.pru0_dataram_base, .pruss_map_size)
579  munmap(.extram_base, .extram_map_size)
580  FOR i AS LONG = 0 TO NUM_PRU_HOSTIRQS - 1
581  IF .fd(i) THEN close_(.fd(i)) : .fd(i) = 0
582  NEXT
583  .mmap_fd = 0
584  END WITH
585 END SUB
586 
587 
588 
599 FUNCTION find_claims CDECL(BYVAL Typ AS UInt32) AS ZSTRING PTR
600 #DEFINE TBUFF_SIZE 32768
601  STATIC AS STRING mux
602  DIM AS STRING*TBUFF_SIZE t
603  VAR fd = open_(KERNEL_PINMUX_PINS, O_RDONLY)
604  IF fd < 0 THEN _
605  fd = open_(KERNEL_PINMUX_PINX, O_RDONLY) : IF fd < 0 THEN RETURN 0
606  VAR r = read_(fd, @t, TBUFF_SIZE)
607  close_(fd)
608  VAR toffs = (PRUIO_AZ_BALL + 1) SHL 1
609  mux = STRING(toffs, 0) & "internal CPU ball" & CHR(0)
610  VAR x = "", m = CAST(Int16 PTR, SADD(mux))
611  FOR i AS INTEGER = 0 TO PRUIO_AZ_BALL : m[i] = toffs : NEXT ' all internal
612  SELECT CASE AS CONST Typ
613  CASE PBB2x36 : x = HEADERPINS_POCKET ' 2x36 headers
614  CASE BB_Blue : x = HEADERPINS_BLUE ' single connectors
615  CASE ELSE : x = HEADERPINS_BB ' BeagleBone 2x46 headers
616  END SELECT : FOR i AS INTEGER = 0 TO LEN(x) - 1 : m[x[i]] = 0 : NEXT ' external
617 ' to parse: "pin 105 (PIN105): (MUX UNCLAIMED) (GPIO UNCLAIMED)"
618  VAR p = CAST(ZSTRING PTR, SADD(t) + 3) _
619  , c = CVL("pin ") _
620  , a = 1, e = INSTR(t, !"\n")
621  WHILE e
622  IF *CAST(Int32 PTR, p + a - 4) = c THEN ' check "pin "
623  VAR n = VALINT(*(p + a)) : IF n > PRUIO_AZ_BALL THEN EXIT WHILE
624  VAR p1 = INSTR(a, t, "): ") + 3
625  IF p1 > 3 THEN ' muxline
626  IF t[p1 - 1] <> ASC("(") THEN ' not "(MUX UNCLAIM..."
627  VAR p2 = INSTR(p1, t, " ") _
628  , own = MID(t, p1, IIF(p2, p2, e) - p1) & CHR(0) _
629  , x = INSTRREV(mux, CHR(0) & own)
630  IF x < toffs THEN x = LEN(mux) : mux &= own ' new entry
631  CAST(Int16 PTR, SADD(mux))[n] = x ' add owner
632  END IF
633  END IF
634  END IF : a = e + 1 : e = INSTR(a, t, !"\n") ' next line
635  WEND : RETURN SADD(mux)
636 END FUNCTION
637 
638 
639 
665 FUNCTION setPin_lkm CDECL( _
666  BYVAL Top AS Pruio_ PTR _
667  , BYVAL Ball AS UInt8 _
668  , BYVAL Mo AS UInt8) AS ZSTRING PTR
669  WITH *Top
670  IF Ball > PRUIO_AZ_BALL THEN .Errr = @"unknown ball number" : RETURN .Errr
671 
672  VAR m = IIF(Mo = PRUIO_PIN_RESET, .BallInit[Ball], Mo)
673  SELECT CASE m
674  CASE .BallConf[Ball] : RETURN 0 ' nothing to do
675  CASE .BallInit[Ball] : IF 24 = (.BallConf[Ball] AND 24) THEN RETURN 0 ' nothing to do
676  END SELECT
677  PUT #.MuxFnr, , HEX((Ball SHL 8) + (m AND &b1111111), 4)
678  SEEK #.MuxFnr, 1 : .BallConf[Ball] = m : RETURN 0
679  END WITH
680 END FUNCTION
681 
682 
683 
700 FUNCTION setPin_lkm_bb CDECL( _
701  BYVAL Top AS Pruio_ PTR _
702  , BYVAL Ball AS UInt8 _
703  , BYVAL Mo AS UInt8) AS ZSTRING PTR
704 
705  WITH *Top
706  STATIC AS UInt8 b, r
707  SELECT CASE AS CONST Ball
708  CASE P9_41 : b = 106
709  CASE P9_42 : b = 104
710  CASE 106 : b = P9_41
711  CASE 104 : b = P9_42
712  CASE ELSE : RETURN setPin_lkm(Top, Ball, Mo)
713  END SELECT : r = .BallGpio(b)
714  WITH *.Gpio
715  .Indx = r SHR 5
716  .Mode = PRUIO_GPIO_IN_0
717  .Mask = 1 SHL (r AND 31)
718  .setGpioSs()
719  END WITH
720  VAR m = IIF(Mo = PRUIO_PIN_RESET, .BallInit[Ball], Mo)
721  SELECT CASE m
722  CASE .BallConf[Ball] : RETURN 0 ' nothing to do
723  CASE .BallInit[Ball] : IF 24 = (.BallConf[Ball] AND 24) THEN RETURN 0 ' nothing to do
724  END SELECT
725 
726  PUT #.MuxFnr, , HEX( b, 2) & "27" _
727  & HEX(Ball, 2) & HEX(m AND &b1111111, 2)
728  SEEK #.MuxFnr, 1
729  .BallConf[b] = PRUIO_GPIO_IN_0 : .BallConf[Ball] = m : RETURN 0
730  END WITH
731 END FUNCTION
732 
733 
734 
752 FUNCTION setPin_save CDECL( _
753  BYVAL Top AS Pruio_ PTR _
754  , BYVAL Ball AS UInt8, BYVAL Mo AS UInt8) AS ZSTRING PTR
755  STATIC AS ZSTRING PTR m
756  STATIC set_func AS setPinFunc
757  STATIC AS STRING e
758 
759  WITH *Top
760  IF 0 = m ORELSE Ball > PRUIO_AZ_BALL THEN ' init
761  set_func = IIF(Top->BbType, @setPin_lkm(), @setPin_lkm_bb())
762  m = find_claims(.BbType)
763  .Errr = IIF(m, 0, @"parsing kernel claims") : RETURN .Errr
764  END IF
765 
766  VAR o = CAST(Int16 PTR, m) : IF 0 = o[Ball] THEN RETURN set_func(Top, Ball, Mo)
767  VAR x = .nameBall(Ball)
768  IF x THEN e = "pin " & *x ELSE e = "ball" & Ball
769  e &= " claimed by: " & *(m + o[Ball]) : .Errr = SADD(e) : RETURN .Errr
770  END WITH
771 END FUNCTION
772 
773 
774 
775 
789 FUNCTION setPin_nogo CDECL( _
790  BYVAL Top AS Pruio_ PTR _
791  , BYVAL Ball AS UInt8 _
792  , BYVAL Mo AS UInt8) AS ZSTRING PTR
793 
794  Top->Errr = @"pinmux missing" : RETURN Top->Errr
795 END FUNCTION
796 
797 
798 
818 FUNCTION setPin_dtbo CDECL( _
819  BYVAL Top AS Pruio_ PTR _
820  , BYVAL Ball AS UInt8 _
821  , BYVAL Mo AS UInt8) AS ZSTRING PTR
822  WITH *Top
823  IF Ball > PRUIO_AZ_BALL THEN _
824  .Errr = @"unknown setPin ball number" : RETURN .Errr
825 
826  VAR m = IIF(Mo = PRUIO_PIN_RESET, .BallInit[Ball], Mo)
827  IF .BallConf[Ball] = m THEN RETURN 0 ' nothing to do
828 
829  SELECT CASE AS CONST .MuxFnr
830  CASE 256 ' kernel 3.8
831  VAR fnam = *.MuxAcc & HEX(Ball, 2)
832  VAR p = DIR(fnam & ".*", fbDirectory)
833  fnam &= MID(p, INSTR(p, "."))
834  VAR fnr = FREEFILE
835  IF OPEN(fnam & "/state" FOR OUTPUT AS fnr) THEN EXIT SELECT
836  PRINT #fnr, "x" & HEX(m, 2)
837  CLOSE #fnr : .BallConf[Ball] = m : RETURN 0
838  CASE 257 ' kernel 4.x
839  VAR fnam = *.MuxAcc & HEX(Ball, 2), fnr = FREEFILE
840  IF OPEN(fnam & "/state" FOR OUTPUT AS fnr) THEN EXIT SELECT
841  PRINT #fnr, "x" & HEX(m, 2)
842  CLOSE #fnr : .BallConf[Ball] = m : RETURN 0
843  CASE ELSE : .Errr = @"no ocp access" : RETURN .Errr
844  END SELECT
845 
846  STATIC AS STRING*30 e = "pinmux failed: P._.. -> x.."
847  VAR x = .nameBall(Ball)
848  IF x THEN MID(e, 16, 5) = *x ELSE MID(e, 16, 5) = "bal" & HEX(Ball, 2)
849  MID(e, 26, 2) = HEX(m, 2) : .Errr = SADD(e) : RETURN .Errr
850  END WITH
851 END FUNCTION
852