From 6fba403b2f749ae0ea64019037fc692f2de1483d Mon Sep 17 00:00:00 2001
From: Gordon Henderson <projects@drogon.net>
Date: Tue, 24 Jun 2014 19:23:31 +0100
Subject: [PATCH] Updates for the Raspnerry Pi Compute Module - changes to the gpio program
 to produce a nicer 'readall' output too.

It also understands new pins 53,54,55 and 56 in wiringPiSetupPhys()
mode to represent the pins on the P5 connector on the Rev 2 Pi's

Changes to pinMode() to allow new modes SOFT_PWM and SOFT_TONE.
---
 gpio/gpio.c         |    9 +++-
 gpio/pins.c         |   11 ++++
 gpio/readall.c      |   59 +++++++++++++++++--
 wiringPi/softPwm.c  |    8 ++-
 wiringPi/softTone.c |   33 ++++++++++-
 wiringPi/softTone.h |    1 +
 wiringPi/wiringPi.c |  156 ++++++++++++++++++++++++++++++++++++++++++++-------
 wiringPi/wiringPi.h |   15 +++++
 8 files changed, 260 insertions(+), 32 deletions(-)

diff --git a/gpio/gpio.c b/gpio/gpio.c
index d941db5..c6021d4 100644
--- a/gpio/gpio.c
+++ b/gpio/gpio.c
@@ -79,6 +79,7 @@ char *usage = "Usage: gpio -v\n"
 	      "       gpio gbw <channel> <value>" ;	// No trailing newline needed here.
 
 
+#ifdef	NOT_FOR_NOW
 /*
  * decodePin:
  *	Decode a pin "number" which can actually be a pin name to represent
@@ -96,6 +97,7 @@ static int decodePin (const char *str)
 
   return 0 ;
 }
+#endif
 
 
 /*
@@ -1042,6 +1044,8 @@ static void doPwmClock (int argc, char *argv [])
 int main (int argc, char *argv [])
 {
   int i ;
+  int model, rev, mem ;
+  char *maker ;
 
   if (getenv ("WIRINGPI_DEBUG") != NULL)
   {
@@ -1086,7 +1090,10 @@ int main (int argc, char *argv [])
     printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ;
     printf ("For details type: %s -warranty\n", argv [0]) ;
     printf ("\n") ;
-    printf ("This Raspberry Pi is a revision %d board.\n", piBoardRev ()) ;
+    piBoardId (&model, &rev, &mem, &maker) ;
+    printf ("Raspberry Pi Details:\n") ;
+    printf ("  Type: %s, Revision: %s, Memory: %dMB, Maker: %s\n", 
+	piModelNames [model], piRevisionNames [rev], mem, maker) ;
     return 0 ;
   }
 
diff --git a/gpio/pins.c b/gpio/pins.c
index 6df3cb2..457922d 100644
--- a/gpio/pins.c
+++ b/gpio/pins.c
@@ -39,6 +39,17 @@ extern int wpMode ;
 
 void doPins (void)
 {
+  int model, rev, mem ;
+  char *maker ;
+
+  piBoardId (&model, &rev, &mem, &maker) ;
+  if (model == PI_MODEL_CM)
+  {
+    printf ("This Raspberry Pi is a Compute Module.\n") ;
+    printf ("    (who knows what's been done to the pins!)\n") ;
+    return ;
+  }
+
   printf ("This Raspberry Pi is a revision %d board.\n", piBoardRev ()) ;
 
   printf (
diff --git a/gpio/readall.c b/gpio/readall.c
index 8fc9f88..b363d3b 100644
--- a/gpio/readall.c
+++ b/gpio/readall.c
@@ -37,6 +37,11 @@
 
 extern int wpMode ;
 
+#ifndef TRUE
+#  define       TRUE    (1==1)
+#  define       FALSE   (1==2)
+#endif
+
 /*
  * doReadallExternal:
  *	A relatively crude way to read the pins on an external device.
@@ -90,7 +95,7 @@ static int wpiToPhys [64] =
    3,  5,				//  8...9
   24, 26, 19, 21, 23,			// 10..14
    8, 10,				// 15..16
-   3,  4,  5,  6,			// 17..20
+  53, 54, 55, 56,			// 17..20
              0,0,0,0,0,0,0,0,0,0,0,	// 20..31
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	// 32..47
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	// 47..63
@@ -115,11 +120,11 @@ static int physToWpi [64] =
   14, 10,
   -1, 11,       // 25, 26
 
-// Padding:
-
                                               -1, -1, -1, -1, -1,       // ... 31
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,       // ... 47
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,       // ... 63
+  -1, -1, -1, -1, -1,							// ... 52
+  28, 29, 30, 31,							// ... 53, 54, 55, 56 - P5
+  -1, -1, -1, -1, -1, -1, -1,						// ... 63
 } ;
 
 static char *physNames [64] = 
@@ -140,9 +145,11 @@ static char *physNames [64] =
   "SCLK",  "CE0",
   "0v",    "CE1",
 
-                                                         NULL,NULL,NULL,NULL,NULL,
-  NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
-  NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+                                                         NULL,NULL,NULL,NULL,NULL,	// ... 31
+  NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,	// ... 47
+  NULL,NULL,NULL,NULL,NULL,								// ... 52
+  "GPIO8", "GPIO9", "GPIO10", "GPIO11",							// ... 53, 54, 55, 56 - P5
+  NULL,NULL,NULL,NULL,NULL,NULL,							// ... 63
 } ;
 
 static void readallPhys (int physPin)
@@ -225,6 +232,38 @@ static void readallPhys (int physPin)
 }
 
 
+int cmReadall (void)
+{
+  int model, rev, mem ;
+  int pin ;
+  char *maker ;
+
+  piBoardId (&model, &rev, &mem, &maker) ;
+  if (model != PI_MODEL_CM)
+    return FALSE ;
+
+  printf ("+-----+------+-------+      +-----+------+-------+\n") ;
+  printf ("| Pin | Mode | Value |      | Pin | Mode | Value |\n") ;
+  printf ("+-----+------+-------+      +-----+------+-------+\n") ;
+
+  for (pin = 0 ; pin < 28 ; ++pin)
+  {
+    printf ("| %3d ", pin) ;
+    printf ("| %-4s ", alts [getAlt (pin)]) ;
+    printf ("| %s  ", digitalRead (pin) == HIGH ? "High" : "Low ") ;
+    printf ("|      ") ;
+    printf ("| %3d ", pin + 28) ;
+    printf ("| %-4s ", alts [getAlt (pin + 28)]) ;
+    printf ("| %s  ", digitalRead (pin + 28) == HIGH ? "High" : "Low ") ;
+    printf ("|\n") ;
+  }
+
+  printf ("+-----+------+-------+      +-----+------+-------+\n") ;
+
+  return TRUE ;
+}
+
+
 void doReadall (void)
 {
   int pin ;
@@ -235,6 +274,9 @@ void doReadall (void)
     return ;
   }
 
+  if (cmReadall ())
+    return ;
+
   /**/ if (wpMode == WPI_MODE_GPIO)
   {
     printf (" +-----+-------+------+----+-Rev%d-----+----+------+-------+-----+\n", piBoardRev ()) ;
@@ -275,6 +317,9 @@ void doReadallOld (void)
     return ;
   }
 
+  if (cmReadall ())
+    return ;
+
   printf ("+----------+-Rev%d-+------+--------+------+-------+\n", piBoardRev ()) ;
   printf ("| wiringPi | GPIO | Phys | Name   | Mode | Value |\n") ;
   printf ("+----------+------+------+--------+------+-------+\n") ;
diff --git a/wiringPi/softPwm.c b/wiringPi/softPwm.c
index 0bde180..3c79ba7 100644
--- a/wiringPi/softPwm.c
+++ b/wiringPi/softPwm.c
@@ -67,11 +67,15 @@ int newPin = -1 ;
 static PI_THREAD (softPwmThread)
 {
   int pin, mark, space ;
+  struct sched_param param ;
+
+  param.sched_priority = sched_get_priority_max (SCHED_RR) ;
+  pthread_setschedparam (pthread_self (), SCHED_RR, &param) ;
 
   pin    = newPin ;
   newPin = -1 ;
 
-  piHiPri (50) ;
+  piHiPri (90) ;
 
   for (;;)
   {
@@ -159,5 +163,5 @@ void softPwmStop (int pin)
     pthread_join   (threads [pin], NULL) ;
     range [pin] = 0 ;
     digitalWrite (pin, LOW) ;
-}
+  }
 }
diff --git a/wiringPi/softTone.c b/wiringPi/softTone.c
index b4a89f8..e2fb737 100644
--- a/wiringPi/softTone.c
+++ b/wiringPi/softTone.c
@@ -36,7 +36,8 @@
 
 #define	PULSE_TIME	100
 
-static int freqs [MAX_PINS] ;
+static int freqs         [MAX_PINS] ;
+static pthread_t threads [MAX_PINS] ;
 
 static int newPin = -1 ;
 
@@ -50,6 +51,10 @@ static int newPin = -1 ;
 static PI_THREAD (softToneThread)
 {
   int pin, freq, halfPeriod ;
+  struct sched_param param ;
+
+  param.sched_priority = sched_get_priority_max (SCHED_RR) ;
+  pthread_setschedparam (pthread_self (), SCHED_RR, &param) ;
 
   pin    = newPin ;
   newPin = -1 ;
@@ -105,17 +110,41 @@ void softToneWrite (int pin, int freq)
 int softToneCreate (int pin)
 {
   int res ;
+  pthread_t myThread ;
 
   pinMode      (pin, OUTPUT) ;
   digitalWrite (pin, LOW) ;
 
+  if (threads [pin] != 0)
+    return -1 ;
+
   freqs [pin] = 0 ;
 
   newPin = pin ;
-  res = piThreadCreate (softToneThread) ;
+  res    = pthread_create (&myThread, NULL, softToneThread, NULL) ;
 
   while (newPin != -1)
     delay (1) ;
 
+  threads [pin] = myThread ;
+
   return res ;
 }
+
+
+/*
+ * softToneStop:
+ *	Stop an existing softTone thread
+ *********************************************************************************
+ */
+
+void softToneStop (int pin)
+{
+  if (threads [pin] != 0)
+  {
+    pthread_cancel (threads [pin]) ;
+    pthread_join   (threads [pin], NULL) ;
+    threads [pin] = 0 ;
+    digitalWrite (pin, LOW) ;
+  }
+}
diff --git a/wiringPi/softTone.h b/wiringPi/softTone.h
index d8b4e54..a93c5af 100644
--- a/wiringPi/softTone.h
+++ b/wiringPi/softTone.h
@@ -31,6 +31,7 @@ extern "C" {
 #endif
 
 extern int  softToneCreate (int pin) ;
+extern void softToneStop   (int pin) ;
 extern void softToneWrite  (int pin, int freq) ;
 
 #ifdef __cplusplus
diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c
index 4660a67..63a8946 100644
--- a/wiringPi/wiringPi.c
+++ b/wiringPi/wiringPi.c
@@ -71,6 +71,7 @@
 #include <sys/ioctl.h>
 
 #include "softPwm.h"
+#include "softTone.h"
 
 #include "wiringPi.h"
 
@@ -272,6 +273,7 @@ static int pinToGpioR2 [64] =
 // physToGpio:
 //	Take a physical pin (1 through 26) and re-map it to the BCM_GPIO pin
 //	Cope for 2 different board revisions here.
+//	Also add in the P5 connector, so the P5 pins are 3,4,5,6, so 53,54,55,56
 
 static int *physToGpio ;
 
@@ -292,8 +294,6 @@ static int physToGpioR1 [64] =
   11,  8,
   -1,  7,	// 25, 26
 
-// Padding:
-
                                               -1, -1, -1, -1, -1,	// ... 31
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	// ... 47
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	// ... 63
@@ -316,11 +316,13 @@ static int physToGpioR2 [64] =
   11,  8,
   -1,  7,	// 25, 26
 
-// Padding:
+// the P5 connector on the Rev 2 boards:
 
                                               -1, -1, -1, -1, -1,	// ... 31
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	// ... 47
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	// ... 63
+  -1, -1, -1, -1, -1,							// ... 52
+  28, 29, 30, 31,							// ... 53, 54, 55, 56 - P5
+  -1, -1, -1, -1, -1, -1, -1,						// ... 63
 } ;
 
 
@@ -547,22 +549,30 @@ int wiringPiFailure (int fatal, const char *message, ...)
  *
  *	Much confusion here )-:
  *	Seems there are some boards with 0000 in them (mistake in manufacture)
- *	and some board with 0005 in them (another mistake in manufacture?)
  *	So the distinction between boards that I can see is:
  *	0000 - Error
- *	0001 - Not used
- *	0002 - Rev 1
- *	0003 - Rev 1
- *	0004 - Rev 2 (Early reports?
- *	0005 - Rev 2 (but error?)
- *	0006 - Rev 2
- *	0008 - Rev 2 - Model A
- *	000e - Rev 2 + 512MB
- *	000f - Rev 2 + 512MB
+ *	0001 - Not used (Compute - default to Rev 2)
+ *	0002 - Model B, Rev 1, 256MB
+ *	0003 - Model B, Rev 1.1, 256MB, Fuses/D14 removed.
+ *	0004 - Model B, Rev 2, 256MB, Sony
+ *	0005 - Model B, Rev 2, 256MB, Qisda
+ *	0006 - Model B, Rev 2, 256MB, Egoman
+ *	0007 - Model A, Rev 2, 256MB, Egoman
+ *	0008 - Model A, Rev 2, 256MB, Sony
+ *	0009 - Model A, Rev 2, 256MB, Qisda
+ *	000d - Model B, Rev 2, 512MB, Egoman
+ *	000e - Model B, Rev 2, 512MB, Sony
+ *	000f - Model B, Rev 2, 512MB, Qisda
+ *	0011 - Pi compute Module
  *
  *	A small thorn is the olde style overvolting - that will add in
  *		1000000
  *
+ *	The Pi compute module has an revision of 0011 - since we only check the
+ *	last digit, then it's 1, therefore it'll default to not 2 or 3 for a
+ *	Rev 1, so will appear as a Rev 2. This is fine for the most part, but
+ *	we'll properly detect the Compute Module later and adjust accordingly.
+ *
  *********************************************************************************
  */
 
@@ -635,6 +645,89 @@ int piBoardRev (void)
 
 
 /*
+ * piBoardId:
+ *	Do more digging into the board revision string as above, but return
+ *	as much details as we can.
+ *********************************************************************************
+ */
+
+const char *piModelNames [] =
+{
+  "Model A",
+  "Model B",
+  "Compute Module",
+} ;
+
+const char *piRevisionNames[] =
+{
+  "1",
+  "1.1",
+  "2",
+} ;
+
+void piBoardId (int *model, int *rev, int *mem, char **maker)
+{
+  FILE *cpuFd ;
+  char line [120] ;
+  char *c ;
+
+  piBoardRev () ;	// Call this first to make sure all's OK. Don't care about the result.
+
+  if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL)
+    piBoardRevOops ("Unable to open /proc/cpuinfo") ;
+
+  while (fgets (line, 120, cpuFd) != NULL)
+    if (strncmp (line, "Revision", 8) == 0)
+      break ;
+
+  fclose (cpuFd) ;
+
+  if (strncmp (line, "Revision", 8) != 0)
+    piBoardRevOops ("No \"Revision\" line") ;
+
+// Chomp trailing CR/NL
+
+  for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c)
+    *c = 0 ;
+  
+  if (wiringPiDebug)
+    printf ("piboardId: Revision string: %s\n", line) ;
+
+// Scan to first digit
+
+  for (c = line ; *c ; ++c)
+    if (isdigit (*c))
+      break ;
+
+// Make sure its long enough
+
+  if (strlen (c) < 4)
+    piBoardRevOops ("Bogus \"Revision\" line") ;
+  
+// Extract last 4 characters:
+
+  c = c + strlen (c) - 4 ;
+
+// Fill out the replys as appropriate
+
+  /**/ if (strcmp (c, "0002") == 0) { *model = 1 ; *rev = 0 ; *mem = 256 ; *maker = "China"  ; }
+  else if (strcmp (c, "0003") == 0) { *model = 1 ; *rev = 1 ; *mem = 256 ; *maker = "China"  ; }
+  else if (strcmp (c, "0004") == 0) { *model = 1 ; *rev = 2 ; *mem = 256 ; *maker = "Sony"   ; }
+  else if (strcmp (c, "0005") == 0) { *model = 1 ; *rev = 2 ; *mem = 256 ; *maker = "Qisda"  ; }
+  else if (strcmp (c, "0006") == 0) { *model = 1 ; *rev = 2 ; *mem = 256 ; *maker = "Egoman" ; }
+  else if (strcmp (c, "0007") == 0) { *model = 0 ; *rev = 2 ; *mem = 256 ; *maker = "Egoman" ; }
+  else if (strcmp (c, "0008") == 0) { *model = 0 ; *rev = 2 ; *mem = 256 ; *maker = "Sony"   ; }
+  else if (strcmp (c, "0009") == 0) { *model = 1 ; *rev = 2 ; *mem = 256 ; *maker = "Qisda"  ; }
+  else if (strcmp (c, "000d") == 0) { *model = 1 ; *rev = 2 ; *mem = 512 ; *maker = "Egoman" ; }
+  else if (strcmp (c, "000e") == 0) { *model = 1 ; *rev = 2 ; *mem = 512 ; *maker = "Sony"   ; }
+  else if (strcmp (c, "000f") == 0) { *model = 1 ; *rev = 2 ; *mem = 512 ; *maker = "Egoman" ; }
+  else if (strcmp (c, "0011") == 0) { *model = 2 ; *rev = 1 ; *mem = 512 ; *maker = "Sony"   ; }
+  else                              { *model = 0 ; *rev = 0 ; *mem =   0 ; *maker = "Unkn"   ; }
+}
+ 
+
+
+/*
  * wpiPinToGpio:
  *	Translate a wiringPi Pin number to native GPIO pin number.
  *	Provided for external support.
@@ -974,7 +1067,8 @@ void pinMode (int pin, int mode)
     else if (wiringPiMode != WPI_MODE_GPIO)
       return ;
 
-    softPwmStop (origPin) ;
+    softPwmStop  (origPin) ;
+    softToneStop (origPin) ;
 
     fSel    = gpioToGPFSEL [pin] ;
     shift   = gpioToShift  [pin] ;
@@ -985,6 +1079,8 @@ void pinMode (int pin, int mode)
       *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (1 << shift) ;
     else if (mode == SOFT_PWM_OUTPUT)
       softPwmCreate (origPin, 0, 100) ;
+    else if (mode == SOFT_TONE_OUTPUT)
+      softToneCreate (origPin) ;
     else if (mode == PWM_OUTPUT)
     {
       if ((alt = gpioToPwmALT [pin]) == 0)	// Not a hardware capable PWM pin
@@ -1376,8 +1472,18 @@ int wiringPiISR (int pin, int mode, void (*function)(void))
 
     if (pid == 0)	// Child, exec
     {
-      execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ;
-      return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ;
+      if (access ("/usr/local/bin/gpio", X_OK))
+      {
+	execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ;
+	return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ;
+      }
+      else if (access ("/usr/bin/gpio", X_OK))
+      {
+	execl ("/usr/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ;
+	return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ;
+      }
+      else
+	return wiringPiFailure (WPI_FATAL, "wiringPiISR: Can't find gpio program\n") ;
     }
     else		// Parent, wait
       wait (NULL) ;
@@ -1538,13 +1644,17 @@ unsigned int micros (void)
  *
  * Default setup: Initialises the system into wiringPi Pin mode and uses the
  *	memory mapped hardware directly.
+ *
+ * Changed now to revert to "gpio" mode if we're running on a Compute Module.
  *********************************************************************************
  */
 
 int wiringPiSetup (void)
 {
-  int      fd ;
-  int      boardRev ;
+  int   fd ;
+  int   boardRev ;
+  int   model, rev, mem ;
+  char *maker ;
 
   if (getenv (ENV_DEBUG) != NULL)
     wiringPiDebug = TRUE ;
@@ -1618,7 +1728,13 @@ int wiringPiSetup (void)
 
   initialiseEpoch () ;
 
-  wiringPiMode = WPI_MODE_PINS ;
+// If we're running on a compute module, then wiringPi pin numbers don't really many anything...
+
+  piBoardId (&model, &rev, &mem, &maker) ;
+  if (model == PI_MODEL_CM)
+    wiringPiMode = WPI_MODE_GPIO ;
+  else
+    wiringPiMode = WPI_MODE_PINS ;
 
   return 0 ;
 }
diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h
index 4eea3e5..5117cc9 100644
--- a/wiringPi/wiringPi.h
+++ b/wiringPi/wiringPi.h
@@ -43,6 +43,7 @@
 #define	PWM_OUTPUT		 2
 #define	GPIO_CLOCK		 3
 #define	SOFT_PWM_OUTPUT		 4
+#define	SOFT_TONE_OUTPUT	 5
 
 #define	LOW			 0
 #define	HIGH			 1
@@ -65,6 +66,13 @@
 #define	INT_EDGE_RISING		2
 #define	INT_EDGE_BOTH		3
 
+// Pi model types
+
+#define	PI_MODEL_A		0
+#define	PI_MODEL_B		1
+#define	PI_MODEL_CM		2
+
+
 // Threads
 
 #define	PI_THREAD(X)	void *X (void *dummy)
@@ -116,6 +124,12 @@ extern struct wiringPiNodeStruct *wiringPiNodes ;
 extern "C" {
 #endif
 
+// Data
+
+extern const char *piModelNames [] ;
+extern const char *piRevisionNames[] ;
+extern const char *piComputeRevisionNames[] ;
+
 // Internal
 
 extern int wiringPiFailure (int fatal, const char *message, ...) ;
@@ -148,6 +162,7 @@ extern int  wiringPiSetupPiFaceForGpioProg (void) ;	// Don't use this - for gpio
 // On-Board Raspberry Pi hardware specific stuff
 
 extern int  piBoardRev          (void) ;
+extern void piBoardId           (int *model, int *rev, int *mem, char **maker) ;
 extern int  wpiPinToGpio        (int wpiPin) ;
 extern int  physPinToGpio       (int physPin) ;
 extern void setPadDrive         (int group, int value) ;
-- 
1.7.2.5

