gpio.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  1. /*
  2. * gpio.c:
  3. * Swiss-Army-Knife, Set-UID command-line interface to the Raspberry
  4. * Pi's GPIO.
  5. * Copyright (c) 2012-2015 Gordon Henderson
  6. ***********************************************************************
  7. * This file is part of wiringPi:
  8. * https://projects.drogon.net/raspberry-pi/wiringpi/
  9. *
  10. * wiringPi is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Lesser General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * wiringPi is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public License
  21. * along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
  22. ***********************************************************************
  23. */
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <stdint.h>
  27. #include <ctype.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <errno.h>
  31. #include <fcntl.h>
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <wiringPi.h>
  35. #include <wpiExtensions.h>
  36. #include <gertboard.h>
  37. #include <piFace.h>
  38. #include "version.h"
  39. extern int wiringPiDebug ;
  40. // External functions I can't be bothered creating a separate .h file for:
  41. extern void doReadall (void) ;
  42. extern void doPins (void) ;
  43. #ifndef TRUE
  44. # define TRUE (1==1)
  45. # define FALSE (1==2)
  46. #endif
  47. #define PI_USB_POWER_CONTROL 38
  48. #define I2CDETECT "/usr/sbin/i2cdetect"
  49. int wpMode ;
  50. char *usage = "Usage: gpio -v\n"
  51. " gpio -h\n"
  52. " gpio [-g|-1] [-x extension:params] ...\n"
  53. " gpio [-p] <read/write/wb> ...\n"
  54. " gpio <read/write/aread/awritewb/pwm/clock/mode> ...\n"
  55. " gpio readall/reset\n"
  56. " gpio unexportall/exports\n"
  57. " gpio export/edge/unexport ...\n"
  58. " gpio wfi <pin> <mode>\n"
  59. " gpio drive <group> <value>\n"
  60. " gpio pwm-bal/pwm-ms \n"
  61. " gpio pwmr <range> \n"
  62. " gpio pwmc <divider> \n"
  63. " gpio load spi/i2c\n"
  64. " gpio unload spi/i2c\n"
  65. " gpio i2cd/i2cdetect\n"
  66. " gpio usbp high/low\n"
  67. " gpio gbr <channel>\n"
  68. " gpio gbw <channel> <value>" ; // No trailing newline needed here.
  69. #ifdef NOT_FOR_NOW
  70. /*
  71. * decodePin:
  72. * Decode a pin "number" which can actually be a pin name to represent
  73. * one of the Pi's on-board pins.
  74. *********************************************************************************
  75. */
  76. static int decodePin (const char *str)
  77. {
  78. // The first case - see if it's a number:
  79. if (isdigit (str [0]))
  80. return atoi (str) ;
  81. return 0 ;
  82. }
  83. #endif
  84. /*
  85. * changeOwner:
  86. * Change the ownership of the file to the real userId of the calling
  87. * program so we can access it.
  88. *********************************************************************************
  89. */
  90. static void changeOwner (char *cmd, char *file)
  91. {
  92. uid_t uid = getuid () ;
  93. uid_t gid = getgid () ;
  94. if (chown (file, uid, gid) != 0)
  95. {
  96. if (errno == ENOENT) // Warn that it's not there
  97. fprintf (stderr, "%s: Warning (not an error, do not report): File not present: %s\n", cmd, file) ;
  98. else
  99. fprintf (stderr, "%s: Warning (not an error): Unable to change ownership of %s: %s\n", cmd, file, strerror (errno)) ;
  100. }
  101. }
  102. /*
  103. * moduleLoaded:
  104. * Return true/false if the supplied module is loaded
  105. *********************************************************************************
  106. */
  107. static int moduleLoaded (char *modName)
  108. {
  109. int len = strlen (modName) ;
  110. int found = FALSE ;
  111. FILE *fd = fopen ("/proc/modules", "r") ;
  112. char line [80] ;
  113. if (fd == NULL)
  114. {
  115. fprintf (stderr, "gpio: Unable to check modules: %s\n", strerror (errno)) ;
  116. exit (1) ;
  117. }
  118. while (fgets (line, 80, fd) != NULL)
  119. {
  120. if (strncmp (line, modName, len) != 0)
  121. continue ;
  122. found = TRUE ;
  123. break ;
  124. }
  125. fclose (fd) ;
  126. return found ;
  127. }
  128. /*
  129. * doLoad:
  130. * Load either the spi or i2c modules and change device ownerships, etc.
  131. *********************************************************************************
  132. */
  133. static void checkDevTree (char *argv [])
  134. {
  135. struct stat statBuf ;
  136. if (stat ("/proc/device-tree", &statBuf) == 0) // We're on a devtree system ...
  137. {
  138. fprintf (stderr,
  139. "%s: Unable to load/unload modules as this Pi has the device tree enabled.\n"
  140. " You need to run the raspi-config program (as root) and select the\n"
  141. " modules (SPI or I2C) that you wish to load/unload there and reboot.\n"
  142. " There is more information here:\n"
  143. " https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=97314\n", argv [0]) ;
  144. exit (1) ;
  145. }
  146. }
  147. static void _doLoadUsage (char *argv [])
  148. {
  149. fprintf (stderr, "Usage: %s load <spi/i2c> [I2C baudrate in Kb/sec]\n", argv [0]) ;
  150. exit (1) ;
  151. }
  152. static void doLoad (int argc, char *argv [])
  153. {
  154. char *module1, *module2 ;
  155. char cmd [80] ;
  156. char *file1, *file2 ;
  157. char args1 [32], args2 [32] ;
  158. checkDevTree (argv) ;
  159. if (argc < 3)
  160. _doLoadUsage (argv) ;
  161. args1 [0] = args2 [0] = 0 ;
  162. /**/ if (strcasecmp (argv [2], "spi") == 0)
  163. {
  164. module1 = "spidev" ;
  165. module2 = "spi_bcm2708" ;
  166. file1 = "/dev/spidev0.0" ;
  167. file2 = "/dev/spidev0.1" ;
  168. if (argc == 4)
  169. {
  170. fprintf (stderr, "%s: Unable to set the buffer size now. Load aborted. Please see the man page.\n", argv [0]) ;
  171. exit (1) ;
  172. }
  173. else if (argc > 4)
  174. _doLoadUsage (argv) ;
  175. }
  176. else if (strcasecmp (argv [2], "i2c") == 0)
  177. {
  178. module1 = "i2c_dev" ;
  179. module2 = "i2c_bcm2708" ;
  180. file1 = "/dev/i2c-0" ;
  181. file2 = "/dev/i2c-1" ;
  182. if (argc == 4)
  183. sprintf (args2, " baudrate=%d", atoi (argv [3]) * 1000) ;
  184. else if (argc > 4)
  185. _doLoadUsage (argv) ;
  186. }
  187. else
  188. _doLoadUsage (argv) ;
  189. if (!moduleLoaded (module1))
  190. {
  191. sprintf (cmd, "/sbin/modprobe %s%s", module1, args1) ;
  192. system (cmd) ;
  193. }
  194. if (!moduleLoaded (module2))
  195. {
  196. sprintf (cmd, "/sbin/modprobe %s%s", module2, args2) ;
  197. system (cmd) ;
  198. }
  199. if (!moduleLoaded (module2))
  200. {
  201. fprintf (stderr, "%s: Unable to load %s\n", argv [0], module2) ;
  202. exit (1) ;
  203. }
  204. sleep (1) ; // To let things get settled
  205. changeOwner (argv [0], file1) ;
  206. changeOwner (argv [0], file2) ;
  207. }
  208. /*
  209. * doUnLoad:
  210. * Un-Load either the spi or i2c modules and change device ownerships, etc.
  211. *********************************************************************************
  212. */
  213. static void _doUnLoadUsage (char *argv [])
  214. {
  215. fprintf (stderr, "Usage: %s unload <spi/i2c>\n", argv [0]) ;
  216. exit (1) ;
  217. }
  218. static void doUnLoad (int argc, char *argv [])
  219. {
  220. char *module1, *module2 ;
  221. char cmd [80] ;
  222. checkDevTree (argv) ;
  223. if (argc != 3)
  224. _doUnLoadUsage (argv) ;
  225. /**/ if (strcasecmp (argv [2], "spi") == 0)
  226. {
  227. module1 = "spidev" ;
  228. module2 = "spi_bcm2708" ;
  229. }
  230. else if (strcasecmp (argv [2], "i2c") == 0)
  231. {
  232. module1 = "i2c_dev" ;
  233. module2 = "i2c_bcm2708" ;
  234. }
  235. else
  236. _doUnLoadUsage (argv) ;
  237. if (moduleLoaded (module1))
  238. {
  239. sprintf (cmd, "/sbin/rmmod %s", module1) ;
  240. system (cmd) ;
  241. }
  242. if (moduleLoaded (module2))
  243. {
  244. sprintf (cmd, "/sbin/rmmod %s", module2) ;
  245. system (cmd) ;
  246. }
  247. }
  248. /*
  249. * doI2Cdetect:
  250. * Run the i2cdetect command with the right runes for this Pi revision
  251. *********************************************************************************
  252. */
  253. static void doI2Cdetect (int argc, char *argv [])
  254. {
  255. int port = piBoardRev () == 1 ? 0 : 1 ;
  256. char command [128] ;
  257. struct stat statBuf ;
  258. if (stat (I2CDETECT, &statBuf) < 0)
  259. {
  260. fprintf (stderr, "%s: Unable to find i2cdetect command: %s\n", argv [0], strerror (errno)) ;
  261. return ;
  262. }
  263. if (!moduleLoaded ("i2c_dev"))
  264. {
  265. fprintf (stderr, "%s: The I2C kernel module(s) are not loaded.\n", argv [0]) ;
  266. return ;
  267. }
  268. sprintf (command, "%s -y %d", I2CDETECT, port) ;
  269. if (system (command) < 0)
  270. fprintf (stderr, "%s: Unable to run i2cdetect: %s\n", argv [0], strerror (errno)) ;
  271. }
  272. /*
  273. * doExports:
  274. * List all GPIO exports
  275. *********************************************************************************
  276. */
  277. static void doExports (int argc, char *argv [])
  278. {
  279. int fd ;
  280. int i, l, first ;
  281. char fName [128] ;
  282. char buf [16] ;
  283. for (first = 0, i = 0 ; i < 64 ; ++i) // Crude, but effective
  284. {
  285. // Try to read the direction
  286. sprintf (fName, "/sys/class/gpio/gpio%d/direction", i) ;
  287. if ((fd = open (fName, O_RDONLY)) == -1)
  288. continue ;
  289. if (first == 0)
  290. {
  291. ++first ;
  292. printf ("GPIO Pins exported:\n") ;
  293. }
  294. printf ("%4d: ", i) ;
  295. if ((l = read (fd, buf, 16)) == 0)
  296. sprintf (buf, "%s", "?") ;
  297. buf [l] = 0 ;
  298. if ((buf [strlen (buf) - 1]) == '\n')
  299. buf [strlen (buf) - 1] = 0 ;
  300. printf ("%-3s", buf) ;
  301. close (fd) ;
  302. // Try to Read the value
  303. sprintf (fName, "/sys/class/gpio/gpio%d/value", i) ;
  304. if ((fd = open (fName, O_RDONLY)) == -1)
  305. {
  306. printf ("No Value file (huh?)\n") ;
  307. continue ;
  308. }
  309. if ((l = read (fd, buf, 16)) == 0)
  310. sprintf (buf, "%s", "?") ;
  311. buf [l] = 0 ;
  312. if ((buf [strlen (buf) - 1]) == '\n')
  313. buf [strlen (buf) - 1] = 0 ;
  314. printf (" %s", buf) ;
  315. // Read any edge trigger file
  316. sprintf (fName, "/sys/class/gpio/gpio%d/edge", i) ;
  317. if ((fd = open (fName, O_RDONLY)) == -1)
  318. {
  319. printf ("\n") ;
  320. continue ;
  321. }
  322. if ((l = read (fd, buf, 16)) == 0)
  323. sprintf (buf, "%s", "?") ;
  324. buf [l] = 0 ;
  325. if ((buf [strlen (buf) - 1]) == '\n')
  326. buf [strlen (buf) - 1] = 0 ;
  327. printf (" %-8s\n", buf) ;
  328. close (fd) ;
  329. }
  330. }
  331. /*
  332. * doExport:
  333. * gpio export pin mode
  334. * This uses the /sys/class/gpio device interface.
  335. *********************************************************************************
  336. */
  337. void doExport (int argc, char *argv [])
  338. {
  339. FILE *fd ;
  340. int pin ;
  341. char *mode ;
  342. char fName [128] ;
  343. if (argc != 4)
  344. {
  345. fprintf (stderr, "Usage: %s export pin mode\n", argv [0]) ;
  346. exit (1) ;
  347. }
  348. pin = atoi (argv [2]) ;
  349. mode = argv [3] ;
  350. if ((fd = fopen ("/sys/class/gpio/export", "w")) == NULL)
  351. {
  352. fprintf (stderr, "%s: Unable to open GPIO export interface: %s\n", argv [0], strerror (errno)) ;
  353. exit (1) ;
  354. }
  355. fprintf (fd, "%d\n", pin) ;
  356. fclose (fd) ;
  357. sprintf (fName, "/sys/class/gpio/gpio%d/direction", pin) ;
  358. if ((fd = fopen (fName, "w")) == NULL)
  359. {
  360. fprintf (stderr, "%s: Unable to open GPIO direction interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
  361. exit (1) ;
  362. }
  363. /**/ if ((strcasecmp (mode, "in") == 0) || (strcasecmp (mode, "input") == 0))
  364. fprintf (fd, "in\n") ;
  365. else if ((strcasecmp (mode, "out") == 0) || (strcasecmp (mode, "output") == 0))
  366. fprintf (fd, "out\n") ;
  367. else if ((strcasecmp (mode, "high") == 0) || (strcasecmp (mode, "up") == 0))
  368. fprintf (fd, "high\n") ;
  369. else if ((strcasecmp (mode, "low") == 0) || (strcasecmp (mode, "down") == 0))
  370. fprintf (fd, "low\n") ;
  371. else
  372. {
  373. fprintf (stderr, "%s: Invalid mode: %s. Should be in, out, high or low\n", argv [1], mode) ;
  374. exit (1) ;
  375. }
  376. fclose (fd) ;
  377. // Change ownership so the current user can actually use it
  378. sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
  379. changeOwner (argv [0], fName) ;
  380. sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
  381. changeOwner (argv [0], fName) ;
  382. }
  383. /*
  384. * doWfi:
  385. * gpio wfi pin mode
  386. * Wait for Interrupt on a given pin.
  387. * Slight cheat here - it's easier to actually use ISR now (which calls
  388. * gpio to set the pin modes!) then we simply sleep, and expect the thread
  389. * to exit the program. Crude but effective.
  390. *********************************************************************************
  391. */
  392. static void wfi (void)
  393. { exit (0) ; }
  394. void doWfi (int argc, char *argv [])
  395. {
  396. int pin, mode ;
  397. if (argc != 4)
  398. {
  399. fprintf (stderr, "Usage: %s wfi pin mode\n", argv [0]) ;
  400. exit (1) ;
  401. }
  402. pin = atoi (argv [2]) ;
  403. /**/ if (strcasecmp (argv [3], "rising") == 0) mode = INT_EDGE_RISING ;
  404. else if (strcasecmp (argv [3], "falling") == 0) mode = INT_EDGE_FALLING ;
  405. else if (strcasecmp (argv [3], "both") == 0) mode = INT_EDGE_BOTH ;
  406. else
  407. {
  408. fprintf (stderr, "%s: wfi: Invalid mode: %s. Should be rising, falling or both\n", argv [1], argv [3]) ;
  409. exit (1) ;
  410. }
  411. if (wiringPiISR (pin, mode, &wfi) < 0)
  412. {
  413. fprintf (stderr, "%s: wfi: Unable to setup ISR: %s\n", argv [1], strerror (errno)) ;
  414. exit (1) ;
  415. }
  416. for (;;)
  417. delay (9999) ;
  418. }
  419. /*
  420. * doEdge:
  421. * gpio edge pin mode
  422. * Easy access to changing the edge trigger on a GPIO pin
  423. * This uses the /sys/class/gpio device interface.
  424. *********************************************************************************
  425. */
  426. void doEdge (int argc, char *argv [])
  427. {
  428. FILE *fd ;
  429. int pin ;
  430. char *mode ;
  431. char fName [128] ;
  432. if (argc != 4)
  433. {
  434. fprintf (stderr, "Usage: %s edge pin mode\n", argv [0]) ;
  435. exit (1) ;
  436. }
  437. pin = atoi (argv [2]) ;
  438. mode = argv [3] ;
  439. // Export the pin and set direction to input
  440. if ((fd = fopen ("/sys/class/gpio/export", "w")) == NULL)
  441. {
  442. fprintf (stderr, "%s: Unable to open GPIO export interface: %s\n", argv [0], strerror (errno)) ;
  443. exit (1) ;
  444. }
  445. fprintf (fd, "%d\n", pin) ;
  446. fclose (fd) ;
  447. sprintf (fName, "/sys/class/gpio/gpio%d/direction", pin) ;
  448. if ((fd = fopen (fName, "w")) == NULL)
  449. {
  450. fprintf (stderr, "%s: Unable to open GPIO direction interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
  451. exit (1) ;
  452. }
  453. fprintf (fd, "in\n") ;
  454. fclose (fd) ;
  455. sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
  456. if ((fd = fopen (fName, "w")) == NULL)
  457. {
  458. fprintf (stderr, "%s: Unable to open GPIO edge interface for pin %d: %s\n", argv [0], pin, strerror (errno)) ;
  459. exit (1) ;
  460. }
  461. /**/ if (strcasecmp (mode, "none") == 0) fprintf (fd, "none\n") ;
  462. else if (strcasecmp (mode, "rising") == 0) fprintf (fd, "rising\n") ;
  463. else if (strcasecmp (mode, "falling") == 0) fprintf (fd, "falling\n") ;
  464. else if (strcasecmp (mode, "both") == 0) fprintf (fd, "both\n") ;
  465. else
  466. {
  467. fprintf (stderr, "%s: Invalid mode: %s. Should be none, rising, falling or both\n", argv [1], mode) ;
  468. exit (1) ;
  469. }
  470. // Change ownership of the value and edge files, so the current user can actually use it!
  471. sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
  472. changeOwner (argv [0], fName) ;
  473. sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
  474. changeOwner (argv [0], fName) ;
  475. fclose (fd) ;
  476. }
  477. /*
  478. * doUnexport:
  479. * gpio unexport pin
  480. * This uses the /sys/class/gpio device interface.
  481. *********************************************************************************
  482. */
  483. void doUnexport (int argc, char *argv [])
  484. {
  485. FILE *fd ;
  486. int pin ;
  487. if (argc != 3)
  488. {
  489. fprintf (stderr, "Usage: %s unexport pin\n", argv [0]) ;
  490. exit (1) ;
  491. }
  492. pin = atoi (argv [2]) ;
  493. if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL)
  494. {
  495. fprintf (stderr, "%s: Unable to open GPIO export interface\n", argv [0]) ;
  496. exit (1) ;
  497. }
  498. fprintf (fd, "%d\n", pin) ;
  499. fclose (fd) ;
  500. }
  501. /*
  502. * doUnexportAll:
  503. * gpio unexportall
  504. * Un-Export all the GPIO pins.
  505. * This uses the /sys/class/gpio device interface.
  506. *********************************************************************************
  507. */
  508. void doUnexportall (char *progName)
  509. {
  510. FILE *fd ;
  511. int pin ;
  512. for (pin = 0 ; pin < 63 ; ++pin)
  513. {
  514. if ((fd = fopen ("/sys/class/gpio/unexport", "w")) == NULL)
  515. {
  516. fprintf (stderr, "%s: Unable to open GPIO export interface\n", progName) ;
  517. exit (1) ;
  518. }
  519. fprintf (fd, "%d\n", pin) ;
  520. fclose (fd) ;
  521. }
  522. }
  523. /*
  524. * doReset:
  525. * Reset the GPIO pins - as much as we can do
  526. *********************************************************************************
  527. */
  528. static void doReset (char *progName)
  529. {
  530. printf ("GPIO Reset is dangerous and has been removed from the gpio command.\n") ;
  531. printf (" - Please write a shell-script to reset the GPIO pins into the state\n") ;
  532. printf (" that you need them in for your applications.\n") ;
  533. }
  534. /*
  535. * doMode:
  536. * gpio mode pin mode ...
  537. *********************************************************************************
  538. */
  539. void doMode (int argc, char *argv [])
  540. {
  541. int pin ;
  542. char *mode ;
  543. if (argc != 4)
  544. {
  545. fprintf (stderr, "Usage: %s mode pin mode\n", argv [0]) ;
  546. exit (1) ;
  547. }
  548. pin = atoi (argv [2]) ;
  549. mode = argv [3] ;
  550. /**/ if (strcasecmp (mode, "in") == 0) pinMode (pin, INPUT) ;
  551. else if (strcasecmp (mode, "input") == 0) pinMode (pin, INPUT) ;
  552. else if (strcasecmp (mode, "out") == 0) pinMode (pin, OUTPUT) ;
  553. else if (strcasecmp (mode, "output") == 0) pinMode (pin, OUTPUT) ;
  554. else if (strcasecmp (mode, "pwm") == 0) pinMode (pin, PWM_OUTPUT) ;
  555. else if (strcasecmp (mode, "pwmTone") == 0) pinMode (pin, PWM_TONE_OUTPUT) ;
  556. else if (strcasecmp (mode, "clock") == 0) pinMode (pin, GPIO_CLOCK) ;
  557. else if (strcasecmp (mode, "up") == 0) pullUpDnControl (pin, PUD_UP) ;
  558. else if (strcasecmp (mode, "down") == 0) pullUpDnControl (pin, PUD_DOWN) ;
  559. else if (strcasecmp (mode, "tri") == 0) pullUpDnControl (pin, PUD_OFF) ;
  560. else if (strcasecmp (mode, "off") == 0) pullUpDnControl (pin, PUD_OFF) ;
  561. else if (strcasecmp (mode, "alt0") == 0) pinModeAlt (pin, 0b100) ;
  562. else if (strcasecmp (mode, "alt1") == 0) pinModeAlt (pin, 0b101) ;
  563. else if (strcasecmp (mode, "alt2") == 0) pinModeAlt (pin, 0b110) ;
  564. else if (strcasecmp (mode, "alt3") == 0) pinModeAlt (pin, 0b111) ;
  565. else if (strcasecmp (mode, "alt4") == 0) pinModeAlt (pin, 0b011) ;
  566. else if (strcasecmp (mode, "alt5") == 0) pinModeAlt (pin, 0b010) ;
  567. else
  568. {
  569. fprintf (stderr, "%s: Invalid mode: %s. Should be in/out/pwm/clock/up/down/tri\n", argv [1], mode) ;
  570. exit (1) ;
  571. }
  572. }
  573. /*
  574. * doPadDrive:
  575. * gpio drive group value
  576. *********************************************************************************
  577. */
  578. static void doPadDrive (int argc, char *argv [])
  579. {
  580. int group, val ;
  581. if (argc != 4)
  582. {
  583. fprintf (stderr, "Usage: %s drive group value\n", argv [0]) ;
  584. exit (1) ;
  585. }
  586. group = atoi (argv [2]) ;
  587. val = atoi (argv [3]) ;
  588. if ((group < 0) || (group > 2))
  589. {
  590. fprintf (stderr, "%s: drive group not 0, 1 or 2: %d\n", argv [0], group) ;
  591. exit (1) ;
  592. }
  593. if ((val < 0) || (val > 7))
  594. {
  595. fprintf (stderr, "%s: drive value not 0-7: %d\n", argv [0], val) ;
  596. exit (1) ;
  597. }
  598. setPadDrive (group, val) ;
  599. }
  600. /*
  601. * doUsbP:
  602. * Control USB Power - High (1.2A) or Low (600mA)
  603. * gpio usbp high/low
  604. *********************************************************************************
  605. */
  606. static void doUsbP (int argc, char *argv [])
  607. {
  608. int model, rev, mem, maker, overVolted ;
  609. if (argc != 3)
  610. {
  611. fprintf (stderr, "Usage: %s usbp high|low\n", argv [0]) ;
  612. exit (1) ;
  613. }
  614. // Make sure we're on a B+
  615. piBoardId (&model, &rev, &mem, &maker, &overVolted) ;
  616. if (model != PI_MODEL_BP)
  617. {
  618. fprintf (stderr, "USB power contol is applicable to B+ boards only.\n") ;
  619. exit (1) ;
  620. }
  621. // Need to force BCM_GPIO mode:
  622. wiringPiSetupGpio () ;
  623. if ((strcasecmp (argv [2], "high") == 0) || (strcasecmp (argv [2], "hi") == 0))
  624. {
  625. digitalWrite (PI_USB_POWER_CONTROL, 1) ;
  626. pinMode (PI_USB_POWER_CONTROL, OUTPUT) ;
  627. printf ("Switched to HIGH current USB (1.2A)\n") ;
  628. return ;
  629. }
  630. if ((strcasecmp (argv [2], "low") == 0) || (strcasecmp (argv [2], "lo") == 0))
  631. {
  632. digitalWrite (PI_USB_POWER_CONTROL, 0) ;
  633. pinMode (PI_USB_POWER_CONTROL, OUTPUT) ;
  634. printf ("Switched to LOW current USB (600mA)\n") ;
  635. return ;
  636. }
  637. fprintf (stderr, "Usage: %s usbp high|low\n", argv [0]) ;
  638. exit (1) ;
  639. }
  640. /*
  641. * doGbw:
  642. * gpio gbw channel value
  643. * Gertboard Write - To the Analog output
  644. *********************************************************************************
  645. */
  646. static void doGbw (int argc, char *argv [])
  647. {
  648. int channel, value ;
  649. if (argc != 4)
  650. {
  651. fprintf (stderr, "Usage: %s gbw <channel> <value>\n", argv [0]) ;
  652. exit (1) ;
  653. }
  654. channel = atoi (argv [2]) ;
  655. value = atoi (argv [3]) ;
  656. if ((channel < 0) || (channel > 1))
  657. {
  658. fprintf (stderr, "%s: gbw: Channel number must be 0 or 1\n", argv [0]) ;
  659. exit (1) ;
  660. }
  661. if ((value < 0) || (value > 255))
  662. {
  663. fprintf (stderr, "%s: gbw: Value must be from 0 to 255\n", argv [0]) ;
  664. exit (1) ;
  665. }
  666. if (gertboardAnalogSetup (64) < 0)
  667. {
  668. fprintf (stderr, "Unable to initialise the Gertboard SPI interface: %s\n", strerror (errno)) ;
  669. exit (1) ;
  670. }
  671. analogWrite (64 + channel, value) ;
  672. }
  673. /*
  674. * doGbr:
  675. * gpio gbr channel
  676. * From the analog input
  677. *********************************************************************************
  678. */
  679. static void doGbr (int argc, char *argv [])
  680. {
  681. int channel ;
  682. if (argc != 3)
  683. {
  684. fprintf (stderr, "Usage: %s gbr <channel>\n", argv [0]) ;
  685. exit (1) ;
  686. }
  687. channel = atoi (argv [2]) ;
  688. if ((channel < 0) || (channel > 1))
  689. {
  690. fprintf (stderr, "%s: gbr: Channel number must be 0 or 1\n", argv [0]) ;
  691. exit (1) ;
  692. }
  693. if (gertboardAnalogSetup (64) < 0)
  694. {
  695. fprintf (stderr, "Unable to initialise the Gertboard SPI interface: %s\n", strerror (errno)) ;
  696. exit (1) ;
  697. }
  698. printf ("%d\n", analogRead (64 + channel)) ;
  699. }
  700. /*
  701. * doWrite:
  702. * gpio write pin value
  703. *********************************************************************************
  704. */
  705. static void doWrite (int argc, char *argv [])
  706. {
  707. int pin, val ;
  708. if (argc != 4)
  709. {
  710. fprintf (stderr, "Usage: %s write pin value\n", argv [0]) ;
  711. exit (1) ;
  712. }
  713. pin = atoi (argv [2]) ;
  714. /**/ if ((strcasecmp (argv [3], "up") == 0) || (strcasecmp (argv [3], "on") == 0))
  715. val = 1 ;
  716. else if ((strcasecmp (argv [3], "down") == 0) || (strcasecmp (argv [3], "off") == 0))
  717. val = 0 ;
  718. else
  719. val = atoi (argv [3]) ;
  720. /**/ if (val == 0)
  721. digitalWrite (pin, LOW) ;
  722. else
  723. digitalWrite (pin, HIGH) ;
  724. }
  725. /*
  726. * doAwriterite:
  727. * gpio awrite pin value
  728. *********************************************************************************
  729. */
  730. static void doAwrite (int argc, char *argv [])
  731. {
  732. int pin, val ;
  733. if (argc != 4)
  734. {
  735. fprintf (stderr, "Usage: %s awrite pin value\n", argv [0]) ;
  736. exit (1) ;
  737. }
  738. pin = atoi (argv [2]) ;
  739. val = atoi (argv [3]) ;
  740. analogWrite (pin, val) ;
  741. }
  742. /*
  743. * doWriteByte:
  744. * gpio write value
  745. *********************************************************************************
  746. */
  747. static void doWriteByte (int argc, char *argv [])
  748. {
  749. int val ;
  750. if (argc != 3)
  751. {
  752. fprintf (stderr, "Usage: %s wb value\n", argv [0]) ;
  753. exit (1) ;
  754. }
  755. val = (int)strtol (argv [2], NULL, 0) ;
  756. digitalWriteByte (val) ;
  757. }
  758. /*
  759. * doRead:
  760. * Read a pin and return the value
  761. *********************************************************************************
  762. */
  763. void doRead (int argc, char *argv [])
  764. {
  765. int pin, val ;
  766. if (argc != 3)
  767. {
  768. fprintf (stderr, "Usage: %s read pin\n", argv [0]) ;
  769. exit (1) ;
  770. }
  771. pin = atoi (argv [2]) ;
  772. val = digitalRead (pin) ;
  773. printf ("%s\n", val == 0 ? "0" : "1") ;
  774. }
  775. /*
  776. * doAread:
  777. * Read an analog pin and return the value
  778. *********************************************************************************
  779. */
  780. void doAread (int argc, char *argv [])
  781. {
  782. if (argc != 3)
  783. {
  784. fprintf (stderr, "Usage: %s aread pin\n", argv [0]) ;
  785. exit (1) ;
  786. }
  787. printf ("%d\n", analogRead (atoi (argv [2]))) ;
  788. }
  789. /*
  790. * doToggle:
  791. * Toggle an IO pin
  792. *********************************************************************************
  793. */
  794. void doToggle (int argc, char *argv [])
  795. {
  796. int pin ;
  797. if (argc != 3)
  798. {
  799. fprintf (stderr, "Usage: %s toggle pin\n", argv [0]) ;
  800. exit (1) ;
  801. }
  802. pin = atoi (argv [2]) ;
  803. digitalWrite (pin, !digitalRead (pin)) ;
  804. }
  805. /*
  806. * doPwmTone:
  807. * Output a tone in a PWM pin
  808. *********************************************************************************
  809. */
  810. void doPwmTone (int argc, char *argv [])
  811. {
  812. int pin, freq ;
  813. if (argc != 4)
  814. {
  815. fprintf (stderr, "Usage: %s pwmTone <pin> <freq>\n", argv [0]) ;
  816. exit (1) ;
  817. }
  818. pin = atoi (argv [2]) ;
  819. freq = atoi (argv [3]) ;
  820. pwmToneWrite (pin, freq) ;
  821. }
  822. /*
  823. * doClock:
  824. * Output a clock on a pin
  825. *********************************************************************************
  826. */
  827. void doClock (int argc, char *argv [])
  828. {
  829. int pin, freq ;
  830. if (argc != 4)
  831. {
  832. fprintf (stderr, "Usage: %s clock <pin> <freq>\n", argv [0]) ;
  833. exit (1) ;
  834. }
  835. pin = atoi (argv [2]) ;
  836. freq = atoi (argv [3]) ;
  837. gpioClockSet (pin, freq) ;
  838. }
  839. /*
  840. * doPwm:
  841. * Output a PWM value on a pin
  842. *********************************************************************************
  843. */
  844. void doPwm (int argc, char *argv [])
  845. {
  846. int pin, val ;
  847. if (argc != 4)
  848. {
  849. fprintf (stderr, "Usage: %s pwm <pin> <value>\n", argv [0]) ;
  850. exit (1) ;
  851. }
  852. pin = atoi (argv [2]) ;
  853. val = atoi (argv [3]) ;
  854. pwmWrite (pin, val) ;
  855. }
  856. /*
  857. * doPwmMode: doPwmRange: doPwmClock:
  858. * Change the PWM mode, range and clock divider values
  859. *********************************************************************************
  860. */
  861. static void doPwmMode (int mode)
  862. {
  863. pwmSetMode (mode) ;
  864. }
  865. static void doPwmRange (int argc, char *argv [])
  866. {
  867. unsigned int range ;
  868. if (argc != 3)
  869. {
  870. fprintf (stderr, "Usage: %s pwmr <range>\n", argv [0]) ;
  871. exit (1) ;
  872. }
  873. range = (unsigned int)strtoul (argv [2], NULL, 10) ;
  874. if (range == 0)
  875. {
  876. fprintf (stderr, "%s: range must be > 0\n", argv [0]) ;
  877. exit (1) ;
  878. }
  879. pwmSetRange (range) ;
  880. }
  881. static void doPwmClock (int argc, char *argv [])
  882. {
  883. unsigned int clock ;
  884. if (argc != 3)
  885. {
  886. fprintf (stderr, "Usage: %s pwmc <clock>\n", argv [0]) ;
  887. exit (1) ;
  888. }
  889. clock = (unsigned int)strtoul (argv [2], NULL, 10) ;
  890. if ((clock < 1) || (clock > 4095))
  891. {
  892. fprintf (stderr, "%s: clock must be between 0 and 4096\n", argv [0]) ;
  893. exit (1) ;
  894. }
  895. pwmSetClock (clock) ;
  896. }
  897. /*
  898. * doVersion:
  899. * Handle the ever more complicated version command
  900. *********************************************************************************
  901. */
  902. static void doVersion (char *argv [])
  903. {
  904. int model, rev, mem, maker, warranty ;
  905. struct stat statBuf ;
  906. printf ("gpio version: %s\n", VERSION) ;
  907. printf ("Copyright (c) 2012-2015 Gordon Henderson\n") ;
  908. printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ;
  909. printf ("For details type: %s -warranty\n", argv [0]) ;
  910. printf ("\n") ;
  911. piBoardId (&model, &rev, &mem, &maker, &warranty) ;
  912. /*************
  913. if (model == PI_MODEL_UNKNOWN)
  914. {
  915. printf ("Your Raspberry Pi has an unknown model type. Please report this to\n") ;
  916. printf (" projects@drogon.net\n") ;
  917. printf ("with a copy of your /proc/cpuinfo if possible\n") ;
  918. }
  919. else
  920. ***************/
  921. {
  922. printf ("Raspberry Pi Details:\n") ;
  923. printf (" Type: %s, Revision: %s, Memory: %dMB, Maker: %s %s\n",
  924. piModelNames [model], piRevisionNames [rev], piMemorySize [mem], piMakerNames [maker], warranty ? "[Out of Warranty]" : "") ;
  925. // Check for device tree
  926. if (stat ("/proc/device-tree", &statBuf) == 0) // We're on a devtree system ...
  927. printf (" Device tree is enabled.\n") ;
  928. if (stat ("/dev/gpiomem", &statBuf) == 0) // User level GPIO is GO
  929. {
  930. printf (" This Raspberry Pi supports user-level GPIO access.\n") ;
  931. printf (" -> See the man-page for more details\n") ;
  932. }
  933. else
  934. printf (" * Root or sudo required for GPIO access.\n") ;
  935. }
  936. }
  937. /*
  938. * main:
  939. * Start here
  940. *********************************************************************************
  941. */
  942. int main (int argc, char *argv [])
  943. {
  944. int i ;
  945. if (getenv ("WIRINGPI_DEBUG") != NULL)
  946. {
  947. printf ("gpio: wiringPi debug mode enabled\n") ;
  948. wiringPiDebug = TRUE ;
  949. }
  950. if (argc == 1)
  951. {
  952. fprintf (stderr, "%s\n", usage) ;
  953. return 1 ;
  954. }
  955. // Help
  956. if (strcasecmp (argv [1], "-h") == 0)
  957. {
  958. printf ("%s: %s\n", argv [0], usage) ;
  959. return 0 ;
  960. }
  961. // Version & Warranty
  962. // Wish I could remember why I have both -R and -V ...
  963. if ((strcmp (argv [1], "-R") == 0) || (strcmp (argv [1], "-V") == 0))
  964. {
  965. printf ("%d\n", piBoardRev ()) ;
  966. return 0 ;
  967. }
  968. // Version and information
  969. if (strcmp (argv [1], "-v") == 0)
  970. {
  971. doVersion (argv) ;
  972. return 0 ;
  973. }
  974. if (strcasecmp (argv [1], "-warranty") == 0)
  975. {
  976. printf ("gpio version: %s\n", VERSION) ;
  977. printf ("Copyright (c) 2012-2015 Gordon Henderson\n") ;
  978. printf ("\n") ;
  979. printf (" This program is free software; you can redistribute it and/or modify\n") ;
  980. printf (" it under the terms of the GNU Leser General Public License as published\n") ;
  981. printf (" by the Free Software Foundation, either version 3 of the License, or\n") ;
  982. printf (" (at your option) any later version.\n") ;
  983. printf ("\n") ;
  984. printf (" This program is distributed in the hope that it will be useful,\n") ;
  985. printf (" but WITHOUT ANY WARRANTY; without even the implied warranty of\n") ;
  986. printf (" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n") ;
  987. printf (" GNU Lesser General Public License for more details.\n") ;
  988. printf ("\n") ;
  989. printf (" You should have received a copy of the GNU Lesser General Public License\n") ;
  990. printf (" along with this program. If not, see <http://www.gnu.org/licenses/>.\n") ;
  991. printf ("\n") ;
  992. return 0 ;
  993. }
  994. if (geteuid () != 0)
  995. {
  996. fprintf (stderr, "%s: Must be root to run. Program should be suid root. This is an error.\n", argv [0]) ;
  997. return 1 ;
  998. }
  999. // Initial test for /sys/class/gpio operations:
  1000. /**/ if (strcasecmp (argv [1], "exports" ) == 0) { doExports (argc, argv) ; return 0 ; }
  1001. else if (strcasecmp (argv [1], "export" ) == 0) { doExport (argc, argv) ; return 0 ; }
  1002. else if (strcasecmp (argv [1], "edge" ) == 0) { doEdge (argc, argv) ; return 0 ; }
  1003. else if (strcasecmp (argv [1], "unexport" ) == 0) { doUnexport (argc, argv) ; return 0 ; }
  1004. else if (strcasecmp (argv [1], "unexportall") == 0) { doUnexportall (argv [0]) ; return 0 ; }
  1005. // Check for load command:
  1006. if (strcasecmp (argv [1], "load" ) == 0) { doLoad (argc, argv) ; return 0 ; }
  1007. if (strcasecmp (argv [1], "unload" ) == 0) { doUnLoad (argc, argv) ; return 0 ; }
  1008. // Gertboard commands
  1009. if (strcasecmp (argv [1], "gbr" ) == 0) { doGbr (argc, argv) ; return 0 ; }
  1010. if (strcasecmp (argv [1], "gbw" ) == 0) { doGbw (argc, argv) ; return 0 ; }
  1011. // Check for -g argument
  1012. /**/ if (strcasecmp (argv [1], "-g") == 0)
  1013. {
  1014. wiringPiSetupGpio () ;
  1015. for (i = 2 ; i < argc ; ++i)
  1016. argv [i - 1] = argv [i] ;
  1017. --argc ;
  1018. wpMode = WPI_MODE_GPIO ;
  1019. }
  1020. // Check for -1 argument
  1021. else if (strcasecmp (argv [1], "-1") == 0)
  1022. {
  1023. wiringPiSetupPhys () ;
  1024. for (i = 2 ; i < argc ; ++i)
  1025. argv [i - 1] = argv [i] ;
  1026. --argc ;
  1027. wpMode = WPI_MODE_PHYS ;
  1028. }
  1029. // Check for -p argument for PiFace
  1030. else if (strcasecmp (argv [1], "-p") == 0)
  1031. {
  1032. piFaceSetup (200) ;
  1033. for (i = 2 ; i < argc ; ++i)
  1034. argv [i - 1] = argv [i] ;
  1035. --argc ;
  1036. wpMode = WPI_MODE_PIFACE ;
  1037. }
  1038. // Default to wiringPi mode
  1039. else
  1040. {
  1041. wiringPiSetup () ;
  1042. wpMode = WPI_MODE_PINS ;
  1043. }
  1044. // Check for -x argument to load in a new extension
  1045. if (strcasecmp (argv [1], "-x") == 0)
  1046. {
  1047. if (argc < 3)
  1048. {
  1049. fprintf (stderr, "%s: -x missing extension specification.\n", argv [0]) ;
  1050. exit (EXIT_FAILURE) ;
  1051. }
  1052. if (!loadWPiExtension (argv [0], argv [2], TRUE)) // Prints its own error messages
  1053. exit (EXIT_FAILURE) ;
  1054. for (i = 3 ; i < argc ; ++i)
  1055. argv [i - 2] = argv [i] ;
  1056. argc -= 2 ;
  1057. }
  1058. if (argc <= 1)
  1059. {
  1060. fprintf (stderr, "%s: no command given\n", argv [0]) ;
  1061. exit (EXIT_FAILURE) ;
  1062. }
  1063. // Core wiringPi functions
  1064. /**/ if (strcasecmp (argv [1], "mode" ) == 0) doMode (argc, argv) ;
  1065. else if (strcasecmp (argv [1], "read" ) == 0) doRead (argc, argv) ;
  1066. else if (strcasecmp (argv [1], "write" ) == 0) doWrite (argc, argv) ;
  1067. else if (strcasecmp (argv [1], "pwm" ) == 0) doPwm (argc, argv) ;
  1068. else if (strcasecmp (argv [1], "awrite" ) == 0) doAwrite (argc, argv) ;
  1069. else if (strcasecmp (argv [1], "aread" ) == 0) doAread (argc, argv) ;
  1070. // GPIO Nicies
  1071. else if (strcasecmp (argv [1], "toggle" ) == 0) doToggle (argc, argv) ;
  1072. // Pi Specifics
  1073. else if (strcasecmp (argv [1], "pwm-bal" ) == 0) doPwmMode (PWM_MODE_BAL) ;
  1074. else if (strcasecmp (argv [1], "pwm-ms" ) == 0) doPwmMode (PWM_MODE_MS) ;
  1075. else if (strcasecmp (argv [1], "pwmr" ) == 0) doPwmRange (argc, argv) ;
  1076. else if (strcasecmp (argv [1], "pwmc" ) == 0) doPwmClock (argc, argv) ;
  1077. else if (strcasecmp (argv [1], "pwmTone" ) == 0) doPwmTone (argc, argv) ;
  1078. else if (strcasecmp (argv [1], "drive" ) == 0) doPadDrive (argc, argv) ;
  1079. else if (strcasecmp (argv [1], "usbp" ) == 0) doUsbP (argc, argv) ;
  1080. else if (strcasecmp (argv [1], "readall" ) == 0) doReadall () ;
  1081. else if (strcasecmp (argv [1], "nreadall" ) == 0) doReadall () ;
  1082. else if (strcasecmp (argv [1], "pins" ) == 0) doPins () ;
  1083. else if (strcasecmp (argv [1], "i2cdetect") == 0) doI2Cdetect (argc, argv) ;
  1084. else if (strcasecmp (argv [1], "i2cd" ) == 0) doI2Cdetect (argc, argv) ;
  1085. else if (strcasecmp (argv [1], "reset" ) == 0) doReset (argv [0]) ;
  1086. else if (strcasecmp (argv [1], "wb" ) == 0) doWriteByte (argc, argv) ;
  1087. else if (strcasecmp (argv [1], "clock" ) == 0) doClock (argc, argv) ;
  1088. else if (strcasecmp (argv [1], "wfi" ) == 0) doWfi (argc, argv) ;
  1089. else
  1090. {
  1091. fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ;
  1092. exit (EXIT_FAILURE) ;
  1093. }
  1094. return 0 ;
  1095. }