ibutil.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /***************************************************************************
  2. lib/ibutil.c
  3. -------------------
  4. copyright : (C) 2001,2002 by Frank Mori Hess
  5. email : fmhess@users.sourceforge.net
  6. ***************************************************************************/
  7. /***************************************************************************
  8. * *
  9. * This program is free software; you can redistribute it and/or modify *
  10. * it under the terms of the GNU General Public License as published by *
  11. * the Free Software Foundation; either version 2 of the License, or *
  12. * (at your option) any later version. *
  13. * *
  14. ***************************************************************************/
  15. #define _GNU_SOURCE
  16. #include "ib_internal.h"
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <pthread.h>
  21. #include <assert.h>
  22. #include "parse.h"
  23. ibConf_t *ibConfigs[ GPIB_CONFIGS_LENGTH ] = {NULL};
  24. ibConf_t ibFindConfigs[ FIND_CONFIGS_LENGTH ];
  25. int insert_descriptor( ibConf_t p, int ud )
  26. {
  27. int i;
  28. if( ud < 0 )
  29. {
  30. for( i = GPIB_MAX_NUM_BOARDS; i < GPIB_CONFIGS_LENGTH; i++ )
  31. {
  32. if( ibConfigs[ i ] == NULL ) break;
  33. }
  34. if( i == GPIB_CONFIGS_LENGTH )
  35. {
  36. fprintf( stderr, "libgpib: out of room in ibConfigs[]\n" );
  37. setIberr( ENEB ); // ETAB?
  38. return -1;
  39. }
  40. ud = i;
  41. }else
  42. {
  43. if( ud >= GPIB_CONFIGS_LENGTH )
  44. {
  45. fprintf( stderr, "libgpib: bug! tried to allocate past end if ibConfigs array\n" );
  46. setIberr( EDVR );
  47. setIbcnt( EINVAL );
  48. return -1;
  49. }
  50. if( ibConfigs[ ud ] )
  51. {
  52. fprintf( stderr, "libgpib: bug! tried to allocate board descriptor twice\n" );
  53. setIberr( EDVR );
  54. setIbcnt( EINVAL );
  55. return -1;
  56. }
  57. }
  58. ibConfigs[ ud ] = malloc( sizeof( ibConf_t ) );
  59. if( ibConfigs[ ud ] == NULL )
  60. {
  61. fprintf( stderr, "libgpib: out of memory\n" );
  62. setIberr( EDVR );
  63. setIbcnt( ENOMEM );
  64. return -1;
  65. }
  66. init_ibconf(ibConfigs[ ud ]);
  67. /* put entry to the table */
  68. *ibConfigs[ud] = p;
  69. return ud;
  70. }
  71. int setup_global_board_descriptors( void )
  72. {
  73. int i;
  74. int retval = 0;
  75. for( i = 0; i < FIND_CONFIGS_LENGTH; i++ )
  76. {
  77. if(ibFindConfigs[ i ].is_interface && ibFindConfigs[ i ].settings.board >= 0 &&
  78. ibFindConfigs[ i ].settings.board < GPIB_MAX_NUM_BOARDS)
  79. {
  80. if(insert_descriptor( ibFindConfigs[ i ], ibFindConfigs[ i ].settings.board) < 0 )
  81. {
  82. retval = -1;
  83. }
  84. }
  85. }
  86. /* boards use handle 0 */
  87. for( i = 0; i < GPIB_MAX_NUM_BOARDS; i++ )
  88. if( ibConfigs[ i ] )
  89. ibConfigs[ i ]->handle = 0;
  90. return retval;
  91. }
  92. static pthread_mutex_t config_lock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
  93. static void gpib_atfork_prepare(void)
  94. {
  95. int i;
  96. for(i = 0; i < GPIB_CONFIGS_LENGTH; i++)
  97. if(ibConfigs[i])
  98. {
  99. pthread_mutex_lock(&ibConfigs[i]->async.lock);
  100. pthread_mutex_lock(&ibConfigs[i]->async.join_lock);
  101. }
  102. pthread_mutex_lock(&config_lock);
  103. }
  104. static void gpib_atfork_parent(void)
  105. {
  106. int i;
  107. pthread_mutex_unlock(&config_lock);
  108. for(i = 0; i < GPIB_CONFIGS_LENGTH; i++)
  109. if(ibConfigs[i])
  110. {
  111. pthread_mutex_unlock(&ibConfigs[i]->async.join_lock);
  112. pthread_mutex_unlock(&ibConfigs[i]->async.lock);
  113. }
  114. }
  115. static void gpib_atfork_child(void)
  116. {
  117. int i;
  118. pthread_mutex_init(&config_lock, NULL);
  119. for(i = 0; i < GPIB_CONFIGS_LENGTH; i++)
  120. if(ibConfigs[i])
  121. {
  122. pthread_mutex_init(&ibConfigs[i]->async.join_lock, NULL);
  123. pthread_mutex_init(&ibConfigs[i]->async.lock, NULL);
  124. }
  125. }
  126. int ibParseConfigFile( void )
  127. {
  128. int retval = 0;
  129. static volatile int config_parsed = 0;
  130. char *filename, *envptr;
  131. pthread_mutex_lock( &config_lock );
  132. if( config_parsed )
  133. {
  134. pthread_mutex_unlock( &config_lock );
  135. return 0;
  136. }
  137. envptr = getenv("IB_CONFIG");
  138. if( envptr ) filename = envptr;
  139. else filename = DEFAULT_CONFIG_FILE;
  140. retval = parse_gpib_conf( filename, ibFindConfigs, FIND_CONFIGS_LENGTH,
  141. ibBoard, GPIB_MAX_NUM_BOARDS );
  142. if( retval < 0 )
  143. {
  144. pthread_mutex_unlock( &config_lock );
  145. return retval;
  146. }
  147. retval = setup_global_board_descriptors();
  148. config_parsed = 1;
  149. /* be extra safe about dealing with forks */
  150. pthread_atfork(gpib_atfork_prepare, gpib_atfork_parent,
  151. gpib_atfork_child);
  152. pthread_mutex_unlock( &config_lock );
  153. return retval;
  154. }
  155. /**********************************************************************/
  156. int ibGetDescriptor( ibConf_t p )
  157. {
  158. int retval;
  159. /* XXX should go somewhere else XXX check validity of values */
  160. if(p.settings.pad > gpib_addr_max || p.settings.sad > gpib_addr_max)
  161. {
  162. setIberr( ETAB );
  163. return -1;
  164. }
  165. retval = insert_descriptor( p, -1 );
  166. if( retval < 0 )
  167. return retval;
  168. return retval;
  169. }
  170. int ibFindDevIndex( const char *name )
  171. {
  172. int i;
  173. if( strcmp( "", name ) == 0 ) return -1;
  174. for(i = 0; i < FIND_CONFIGS_LENGTH; i++)
  175. {
  176. if(!strcmp(ibFindConfigs[i].name, name)) return i;
  177. }
  178. return -1;
  179. }
  180. static int ibCheckDescriptor( int ud )
  181. {
  182. if( ud < 0 || ud >= GPIB_CONFIGS_LENGTH || ibConfigs[ud] == NULL )
  183. {
  184. fprintf( stderr, "libgpib: invalid descriptor\n" );
  185. setIberr( EDVR );
  186. setIbcnt( EINVAL );
  187. return -1;
  188. }
  189. return 0;
  190. }
  191. void init_descriptor_settings( descriptor_settings_t *settings )
  192. {
  193. settings->pad = -1;
  194. settings->sad = -1;
  195. settings->board = -1;
  196. settings->usec_timeout = 3000000;
  197. settings->spoll_usec_timeout = 1000000;
  198. settings->ppoll_usec_timeout = 2;
  199. settings->eos = 0;
  200. settings->eos_flags = 0;
  201. settings->ppoll_config = 0;
  202. settings->send_eoi = 1;
  203. settings->local_lockout = 0;
  204. settings->local_ppc = 0;
  205. settings->readdr = 0;
  206. }
  207. void init_ibconf( ibConf_t *conf )
  208. {
  209. conf->handle = -1;
  210. memset(conf->name, 0, sizeof(conf->name));
  211. init_descriptor_settings( &conf->defaults );
  212. init_descriptor_settings( &conf->settings );
  213. memset(conf->init_string, 0, sizeof(conf->init_string));
  214. conf->flags = 0;
  215. init_async_op( &conf->async );
  216. conf->end = 0;
  217. conf->is_interface = 0;
  218. conf->board_is_open = 0;
  219. conf->has_lock = 0;
  220. conf->timed_out = 0;
  221. }
  222. int open_gpib_handle( ibConf_t *conf )
  223. {
  224. open_dev_ioctl_t open_cmd;
  225. int retval;
  226. ibBoard_t *board;
  227. if( conf->handle >= 0 ) return 0;
  228. board = interfaceBoard( conf );
  229. open_cmd.handle = -1;
  230. open_cmd.pad = conf->settings.pad;
  231. open_cmd.sad = conf->settings.sad;
  232. open_cmd.is_board = conf->is_interface;
  233. retval = ioctl( board->fileno, IBOPENDEV, &open_cmd );
  234. if( retval < 0 )
  235. {
  236. fprintf( stderr, "libgpib: IBOPENDEV ioctl failed\n" );
  237. setIberr( EDVR );
  238. setIbcnt( errno );
  239. return retval;
  240. }
  241. conf->handle = open_cmd.handle;
  242. return 0;
  243. }
  244. int close_gpib_handle( ibConf_t *conf )
  245. {
  246. close_dev_ioctl_t close_cmd;
  247. int retval;
  248. ibBoard_t *board;
  249. if( conf->handle < 0 ) return 0;
  250. board = interfaceBoard( conf );
  251. close_cmd.handle = conf->handle;
  252. retval = ioctl( board->fileno, IBCLOSEDEV, &close_cmd );
  253. if( retval < 0 )
  254. {
  255. setIberr( EDVR );
  256. setIbcnt( errno );
  257. return retval;
  258. }
  259. conf->handle = -1;
  260. return 0;
  261. }
  262. int gpibi_change_address( ibConf_t *conf, unsigned int pad, int sad )
  263. {
  264. int retval;
  265. ibBoard_t *board;
  266. pad_ioctl_t pad_cmd;
  267. sad_ioctl_t sad_cmd;
  268. board = interfaceBoard( conf );
  269. pad_cmd.handle = conf->handle;
  270. pad_cmd.pad = pad;
  271. retval = ioctl( board->fileno, IBPAD, &pad_cmd );
  272. if( retval < 0 )
  273. {
  274. setIberr( EDVR );
  275. setIbcnt( errno );
  276. return retval;
  277. }
  278. sad_cmd.handle = conf->handle;
  279. sad_cmd.sad = sad;
  280. retval = ioctl( board->fileno, IBSAD, &sad_cmd );
  281. if( retval < 0 )
  282. {
  283. setIberr( EDVR );
  284. setIbcnt( errno );
  285. return retval;
  286. }
  287. conf->settings.pad = pad;
  288. conf->settings.sad = sad;
  289. return 0;
  290. }
  291. int lock_board_mutex( ibBoard_t *board )
  292. {
  293. static const int lock = 1;
  294. int retval;
  295. retval = ioctl( board->fileno, IBMUTEX, &lock );
  296. if( retval < 0 )
  297. {
  298. fprintf( stderr, "libgpib: error locking board mutex!\n");
  299. setIberr( EDVR );
  300. setIbcnt( errno );
  301. }
  302. return retval;
  303. }
  304. int unlock_board_mutex( ibBoard_t *board )
  305. {
  306. static const int unlock = 0;
  307. int retval;
  308. retval = ioctl( board->fileno, IBMUTEX, &unlock );
  309. if( retval < 0 )
  310. {
  311. fprintf( stderr, "libgpib: error unlocking board mutex!\n");
  312. setIberr( EDVR );
  313. setIbcnt( errno );
  314. }
  315. return retval;
  316. }
  317. int conf_lock_board( ibConf_t *conf )
  318. {
  319. ibBoard_t *board;
  320. int retval;
  321. board = interfaceBoard( conf );
  322. assert( conf->has_lock == 0 );
  323. retval = lock_board_mutex( board );
  324. if( retval < 0 ) return retval;
  325. conf->has_lock = 1;
  326. return retval;
  327. }
  328. void conf_unlock_board( ibConf_t *conf )
  329. {
  330. ibBoard_t *board;
  331. int retval;
  332. board = interfaceBoard( conf );
  333. assert( conf->has_lock );
  334. conf->has_lock = 0;
  335. retval = unlock_board_mutex( board );
  336. assert( retval == 0 );
  337. }
  338. ibConf_t * enter_library( int ud )
  339. {
  340. return general_enter_library( ud, 0, 0 );
  341. }
  342. ibConf_t * general_enter_library( int ud, int no_lock_board, int ignore_eoip )
  343. {
  344. ibConf_t *conf;
  345. ibBoard_t *board;
  346. int retval;
  347. retval = ibParseConfigFile();
  348. if(retval < 0)
  349. {
  350. return NULL;
  351. }
  352. setIberr( 0 );
  353. setIbcnt( 0 );
  354. if( ibCheckDescriptor( ud ) < 0 )
  355. {
  356. return NULL;
  357. }
  358. conf = ibConfigs[ ud ];
  359. retval = conf_online( conf, 1 );
  360. if( retval < 0 ) return NULL;
  361. conf->timed_out = 0;
  362. board = interfaceBoard( conf );
  363. if( no_lock_board == 0 )
  364. {
  365. if( ignore_eoip == 0 )
  366. {
  367. pthread_mutex_lock( &conf->async.lock );
  368. if( conf->async.in_progress )
  369. {
  370. pthread_mutex_unlock( &conf->async.lock );
  371. setIberr( EOIP );
  372. return NULL;
  373. }
  374. pthread_mutex_unlock( &conf->async.lock );
  375. }
  376. retval = conf_lock_board( conf );
  377. if( retval < 0 )
  378. {
  379. return NULL;
  380. }
  381. }
  382. return conf;
  383. }
  384. int ibstatus( ibConf_t *conf, int error, int clear_mask, int set_mask )
  385. {
  386. int status = 0;
  387. int retval;
  388. retval = my_wait( conf, 0, clear_mask, set_mask, &status);
  389. if( retval < 0 ) error = 1;
  390. if( error ) status |= ERR;
  391. if( conf->timed_out )
  392. status |= TIMO;
  393. if( conf->end )
  394. status |= END;
  395. setIbsta( status );
  396. return status;
  397. }
  398. int exit_library( int ud, int error )
  399. {
  400. return general_exit_library( ud, error, 0, 0, 0, 0, 0 );
  401. }
  402. int general_exit_library( int ud, int error, int no_sync_globals, int no_update_ibsta,
  403. int status_clear_mask, int status_set_mask, int no_unlock_board )
  404. {
  405. ibConf_t *conf = ibConfigs[ ud ];
  406. ibBoard_t *board;
  407. int status;
  408. if( ibCheckDescriptor( ud ) < 0 )
  409. {
  410. setIbsta( ERR );
  411. if( no_sync_globals == 0 )
  412. sync_globals();
  413. return ERR;
  414. }
  415. board = interfaceBoard( conf );
  416. if( no_update_ibsta )
  417. status = ThreadIbsta();
  418. else
  419. status = ibstatus( conf, error, status_clear_mask, status_set_mask );
  420. if( no_unlock_board == 0 && conf->has_lock )
  421. conf_unlock_board( conf );
  422. if( no_sync_globals == 0 )
  423. sync_globals();
  424. return status;
  425. }
  426. int extractPAD( Addr4882_t address )
  427. {
  428. int pad = address & 0xff;
  429. if( address == NOADDR ) return ADDR_INVALID;
  430. if( pad < 0 || pad > gpib_addr_max ) return ADDR_INVALID;
  431. return pad;
  432. }
  433. int extractSAD( Addr4882_t address )
  434. {
  435. int sad = ( address >> 8 ) & 0xff;
  436. if( address == NOADDR ) return ADDR_INVALID;
  437. if( sad == NO_SAD ) return SAD_DISABLED;
  438. if( ( sad & 0x60 ) == 0 ) return ADDR_INVALID;
  439. sad &= ~0x60;
  440. if( sad < 0 || sad > gpib_addr_max ) return ADDR_INVALID;
  441. return sad;
  442. }
  443. Addr4882_t packAddress( unsigned int pad, int sad )
  444. {
  445. Addr4882_t address;
  446. address = 0;
  447. address |= pad & 0xff;
  448. if( sad >= 0 )
  449. address |= ( ( sad | sad_offset ) << 8 ) & 0xff00;
  450. return address;
  451. }
  452. int addressIsValid( Addr4882_t address )
  453. {
  454. if( address == NOADDR ) return 1;
  455. if( extractPAD( address ) == ADDR_INVALID ||
  456. extractSAD( address ) == ADDR_INVALID )
  457. {
  458. setIberr( EARG );
  459. return 0;
  460. }
  461. return 1;
  462. }
  463. int addressListIsValid( const Addr4882_t addressList[] )
  464. {
  465. int i;
  466. if( addressList == NULL ) return 1;
  467. for( i = 0; addressList[ i ] != NOADDR; i++ )
  468. {
  469. if( addressIsValid( addressList[ i ] ) == 0 )
  470. {
  471. setIbcnt( i );
  472. return 0;
  473. }
  474. }
  475. return 1;
  476. }
  477. unsigned int numAddresses( const Addr4882_t addressList[] )
  478. {
  479. unsigned int count;
  480. if( addressList == NULL )
  481. return 0;
  482. count = 0;
  483. while( addressList[ count ] != NOADDR )
  484. {
  485. count++;
  486. }
  487. return count;
  488. }
  489. int is_cic( const ibBoard_t *board )
  490. {
  491. int retval;
  492. wait_ioctl_t cmd;
  493. cmd.usec_timeout = 0;
  494. cmd.wait_mask = 0;
  495. cmd.clear_mask = 0;
  496. cmd.set_mask = 0;
  497. cmd.pad = NOADDR;
  498. cmd.sad = NOADDR;
  499. cmd.handle = 0;
  500. cmd.ibsta = 0;
  501. retval = ioctl( board->fileno, IBWAIT, &cmd );
  502. if( retval < 0 )
  503. {
  504. setIberr( EDVR );
  505. setIbcnt( errno );
  506. fprintf( stderr, "libgpib: error in is_cic()!\n");
  507. return -1;
  508. }
  509. if( cmd.ibsta & CIC )
  510. return 1;
  511. return 0;
  512. }
  513. int is_system_controller( const ibBoard_t *board )
  514. {
  515. int retval;
  516. board_info_ioctl_t info;
  517. retval = ioctl( board->fileno, IBBOARD_INFO, &info );
  518. if( retval < 0 )
  519. {
  520. fprintf( stderr, "libgpib: error in is_system_controller()!\n");
  521. return retval;
  522. }
  523. return info.is_system_controller;
  524. }
  525. const char* gpib_error_string( int error )
  526. {
  527. static const char* error_descriptions[] =
  528. {
  529. "EDVR 0: OS error",
  530. "ECIC 1: Board not controller in charge",
  531. "ENOL 2: No listeners",
  532. "EADR 3: Improper addressing",
  533. "EARG 4: Bad argument",
  534. "ESAC 5: Board not system controller",
  535. "EABO 6: Operation aborted",
  536. "ENEB 7: Non-existant board",
  537. "EDMA 8: DMA error",
  538. "libgpib: Unknown error code 9",
  539. "EOIP 10: IO operation in progress",
  540. "ECAP 11: Capability does not exist",
  541. "EFSO 12: File system error",
  542. "libgpib: Unknown error code 13",
  543. "EBUS 14: Bus error",
  544. "ESTB 15: Lost status byte",
  545. "ESRQ 16: Stuck service request",
  546. "libgpib: Unknown error code 17",
  547. "libgpib: Unknown error code 18",
  548. "libgpib: Unknown error code 19",
  549. "ETAB 20: Table problem",
  550. };
  551. static const int max_error_code = ETAB;
  552. if( error < 0 || error > max_error_code )
  553. return "libgpib: Unknown error code";
  554. return error_descriptions[ error ];
  555. }