/* * Motorola Background Debug Mode Library * Copyright (C) 1995 W. Eric Norum * Copyright (C) 1998 Chris Johns * * Based on: * 1. `A Background Debug Mode Driver Package for Motorola's * 16-bit and 32-Bit Microcontrollers', Scott Howard, Motorola * Canada, 1993. * 2. `Linux device driver for public domain BDM Inteface', * M. Schraut, Technische Universitaet Muenchen, Lehrstuhl * fuer Prozessrechner, 1995. * * 31-11-1999 Chris Johns (ccj@acm.org) * Extended to support remote operation. See bdmRemote.c for details. * * Extended to support the ColdFire BDM interface using the P&E module * which comes with the EVB. Thanks to David Fiddes who has tested the * driver with the 5206 (5V), 5206e (3.3V) and 5307 devices. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * W. Eric Norum * Saskatchewan Accelerator Laboratory * University of Saskatchewan * 107 North Road * Saskatoon, Saskatchewan, CANADA * S7N 5C6 * * eric@skatter.usask.ca * * Coldfire support by: * Chris Johns * Objective Design Systems * * ccj@acm.org * */ /* * If no remote/local directive is supplied, default to the * existing local only mode. */ #if !defined (BDM_DEVICE_REMOTE) && !defined (BDM_DEVICE_LOCAL) #define BDM_DEVICE_LOCAL #endif #include #include #include #include #include #include #include /* * This test should be done by autoconf. Please fix if you * know how. */ #if !defined (__WIN32__) || defined (__CYGWIN__) #define HAVE_SYSLOG 1 #include #endif #include "BDMlib.h" #if defined (BDM_DEVICE_REMOTE) #include "bdmRemote.h" #endif /* * Provide the driver print interface so any debug IO * does not end up on stdout if the library is embedded * in a server, ie bdmd. */ #define PRINTF bdmPrint /* * If on Cygwin assume Windows. */ #if defined (__WIN32__) || defined (__CYGWIN__) #include "../driver/win/win-bdm.c" #else /* * See if this is an ioperm build. */ #if defined (BDM_IOPERM) #include "../driver/ioperm/ioperm.c" #endif #endif /* * Limit of one BDM per process */ static int bdm_fd = -1; static int cpu = BDM_CPU32; static int iface = BDM_CPU32_PD; /* * The configuration data read from the configuration file. */ static char* config; static size_t config_buffer_size = 0; #if defined (BDM_DEVICE_REMOTE) static int bdmRemote = 0; #endif /* * Have to make global to allow the bdmBFD function have * access. */ const char *bdmIO_lastErrorString = "No BDM error (yet!)"; /* * Debugging */ static int debugFlag = 0; #if HAVE_SYSLOG static int debug_syslog = 0; #endif static const char *const sysregName[BDM_MAX_SYSREG] = { "RPC", "PCC", "SR", "USP", "SSP", "SFC", "DFC", "ATEMP", "FAR", "VBR", "CACR", "ACR0", "ACR1", "RAMBAR", "MBAR", "CSR", "AATR", "TDR", "PBR", "PBMR", "ABHR", "ABLR", "DBR", "DBMR", }; static const char *const regName[] = { "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", }; void bdmLogSyslog (void) { #if HAVE_SYSLOG debug_syslog = 1; #endif } void bdmInfo (const char *format, ...) { va_list ap; va_start (ap, format); #if HAVE_SYSLOG if (debug_syslog) { if (debugFlag) vsyslog (LOG_INFO, format, ap); } else #endif { vfprintf (stderr, format, ap); fflush (stderr); } va_end (ap); } void bdmPrint (const char *format, ...) { va_list ap; va_start (ap, format); if (debugFlag) { #if HAVE_SYSLOG if (debug_syslog) { vsyslog (LOG_INFO, format, ap); } else #endif { fprintf (stderr, "BDM: "); vfprintf (stderr, format, ap); fflush (stderr); } } va_end (ap); } void bdmSetDebugFlag (int flag) { debugFlag = flag; } /* * Verify that device is open */ int bdmCheck (void) { if (bdm_fd < 0) { bdmIO_lastErrorString = "BDM not open"; return 0; } return 1; } /* * Like strerror(), but knows about BDM driver errors, too. */ static const char * bdmStrerror (int error_no) { switch (error_no) { case BDM_FAULT_UNKNOWN: return "Unknown BDM error"; case BDM_FAULT_POWER: return "No power to BDM adapter"; case BDM_FAULT_CABLE: return "BDM cable problem"; case BDM_FAULT_RESPONSE: return "No response to BDM request"; case BDM_FAULT_RESET: return "Target is in RESET state"; case BDM_FAULT_BERR: return "Target Bus Error"; case BDM_FAULT_NVC: return "Invalid target command"; case BDM_FAULT_FORCED_TA: return "Invalid target command - Forced TA"; } #if defined (BDM_DEVICE_REMOTE) return bdmRemoteStrerror (error_no); #else return strerror (error_no); #endif } /* * Do an int-argument BDM ioctl */ int bdmIoctlInt (int code, int *var) { if (!bdmCheck ()) return -1; #if defined (BDM_DEVICE_REMOTE) if (bdmRemote) { if (bdmRemoteIoctlInt (bdm_fd, code, var) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } } else { #endif #if defined (BDM_DEVICE_LOCAL) if (ioctl (bdm_fd, code, var) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } #endif #if defined (BDM_DEVICE_REMOTE) } #endif return 0; } /* * Do a command (no-argument) BDM ioctl */ int bdmIoctlCommand (int code) { if (!bdmCheck ()) return -1; #if defined (BDM_DEVICE_REMOTE) if (bdmRemote) { if (bdmRemoteIoctlCommand (bdm_fd, code) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } } else { #endif #if defined (BDM_DEVICE_LOCAL) if (ioctl (bdm_fd, code, NULL) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } #endif #if defined (BDM_DEVICE_REMOTE) } #endif return 0; } /* * Do a BDMioctl-argument BDM ioctl */ int bdmIoctlIo (int code, struct BDMioctl *ioc) { if (!bdmCheck ()) return -1; #if defined (BDM_DEVICE_REMOTE) if (bdmRemote) { if (bdmRemoteIoctlIo (bdm_fd, code, ioc) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } } else { #endif #if defined (BDM_DEVICE_LOCAL) if (ioctl (bdm_fd, code, ioc) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } #endif #if defined (BDM_DEVICE_REMOTE) } #endif return 0; } /* * Do a BDM read */ int bdmRead (unsigned char *cbuf, unsigned long nbytes) { if (!bdmCheck ()) return -1; #if defined (BDM_DEVICE_REMOTE) if (bdmRemote) { if (bdmRemoteRead (bdm_fd, cbuf, nbytes) != nbytes) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } } else { #endif #if defined (BDM_DEVICE_LOCAL) if (read (bdm_fd, (char*) cbuf, nbytes) != nbytes) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } #endif #if defined (BDM_DEVICE_REMOTE) } #endif return nbytes; } /* * Do a BDM write */ int bdmWrite (unsigned char *cbuf, unsigned long nbytes) { if (!bdmCheck ()) return -1; #if defined (BDM_DEVICE_REMOTE) if (bdmRemote) { if (bdmRemoteWrite (bdm_fd, cbuf, nbytes) != nbytes) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } } else { #endif #if defined (BDM_DEVICE_LOCAL) if (write (bdm_fd, (char*) cbuf, nbytes) != nbytes) { bdmIO_lastErrorString = bdmStrerror (errno); return -1; } #endif #if defined (BDM_DEVICE_REMOTE) } #endif return nbytes; } /* * Read from the target */ static int readTarget (int command, unsigned long address, unsigned long *lp) { struct BDMioctl ioc; ioc.address = address; ioc.value = 0; if (bdmIoctlIo (command, &ioc) < 0) return -1; *lp = ioc.value; return 0; } /* * Write to the target */ static int writeTarget (int command, unsigned long address, unsigned long l) { struct BDMioctl ioc; ioc.address = address; ioc.value = l; if (bdmIoctlIo (command, &ioc) < 0) return -1; return 0; } static int remoteOpen (const char *name) { int fd = -1; #if defined (BDM_DEVICE_REMOTE) if (bdmRemoteName (name)) { bdmRemote = 1; if ((fd = bdmRemoteOpen (name)) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); bdmRemote = 0; } } #endif return fd; } /* * Return string describing most recent error */ const char * bdmErrorString (void) { return bdmIO_lastErrorString; } /* * Append the configuration data. */ static void bdmAppendConfiguration (const char* fname) { FILE* file = fopen (fname, "r"); char line[256]; int count = 0; if (!file) return; if (!config) { config = malloc (512); config_buffer_size = 512; memset (config, 0, config_buffer_size); } while (fgets (line, sizeof (line), file) != NULL) { int length; count++; length = strlen (line); if (length) { int blank = 1; int i; for (i = 0; i < length; i++) { if (line[i] == '\r') { memmove (line + i, line + i + 1, length - i); length--; } if (line[i] == '#') { if (i < (sizeof (line) - 1)) { line[i] = '\n'; i++; } line[i] = '\0'; length = i; } } if (length) { if (line[0] == '\n') continue; if ((line[length - 1] == '\n') && (line[length - 2] == '\\')) { line[length - 2] = '\0'; length -= 2; } } if (!length) continue; if (length >= (config_buffer_size - strlen (config))) { char* new_config = realloc (config, config_buffer_size + 512); if (new_config == NULL) break; config = new_config; config_buffer_size += 512; } strcat (config, line); } } fclose (file); } /* * Read the configuration file. */ void bdmReadConfiguration () { char* env; if (config) return; /* * The configuration file is read local first then $HOME * if $HOME is found or $M68K_BDM_INIT. If not found no * configuration data is read. */ bdmAppendConfiguration (M68K_BDM_INIT_FILE); env = getenv ("HOME"); if (env && strlen (env)) { char* fname = malloc (strlen (env) + 2 + strlen (M68K_BDM_INIT_FILE)); if (fname) { char last; strcpy (fname, env); last = fname[strlen (fname) - 1]; if (last != '/' && last != '\\') strcat (fname, "/"); strcat (fname, M68K_BDM_INIT_FILE); bdmAppendConfiguration (fname); free (fname); } } env = getenv ("M68K_BDM_INIT"); if (env && strlen (env)) bdmAppendConfiguration (M68K_BDM_INIT_FILE); } /* * Skip white space. */ const char* bdmConfigSkipWhiteSpace (const char* text) { while (*text != '\n') { if (!isblank (*text)) break; text++; } return text; } /* * Find matching lines. */ const char* bdmConfigGet (const char* label, const char* last) { const char* next = NULL; if (config) { while (1) { if (last) next = strchr (last, '\n') + 1; else next = config; last = next; if (*next == '\0') { next = NULL; break; } next = bdmConfigSkipWhiteSpace (next); if (strncmp (next, label, strlen (label)) == 0) { next += strlen (label); break; } } } return next; } /* * Open the specified BDM device */ int bdmOpen (const char *user_name) { #if defined (BDM_LIB_CHECKS_VERSION) unsigned int ver; #endif char* name = NULL; const char* mapping = NULL; /* * Load the configurations. */ bdmReadConfiguration (); /* * Map the name if a mapping is provided. */ while ((mapping = bdmConfigGet ("dev", mapping))) { mapping = bdmConfigSkipWhiteSpace (mapping); if (strncmp (mapping, user_name, strlen (user_name)) == 0) { char* lf; mapping += strlen (user_name); name = strdup (bdmConfigSkipWhiteSpace (mapping)); lf = strchr (name, '\n'); if (lf) *lf = '\0'; break; } } if (!name) name = strdup (user_name); if (!name) { bdmIO_lastErrorString = bdmStrerror (ENOMEM); return -1; } /* * Open the interface. Name could be an ip:port address * which results in tring to open a connection to the * the remote server. * * First we try to open a remote connection if remote is * supported. If this fails we attempt to open the driver. */ if (bdm_fd >= 0) { #if defined (BDM_DEVICE_REMOTE) if (bdmRemote) bdmRemoteClose (bdm_fd); #endif #if defined (BDM_DEVICE_LOCAL) else close (bdm_fd); #endif } bdm_fd = -1; if ((bdm_fd = remoteOpen (name)) < 0) { #if !defined (BDM_DEVICE_LOCAL) bdmIO_lastErrorString = bdmStrerror (2); free (name); return -1; #endif } #if defined (BDM_DEVICE_LOCAL) if (bdm_fd < 0) { if ((bdm_fd = open (name, O_RDWR)) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); free (name); return -1; } } #endif free (name); #if defined (BDM_LIB_CHECKS_VERSION) /* * CCJ: This is better done by the user as they produce a better * error message. */ /* * Check the driver version. */ if (bdmGetDrvVersion (&ver) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); bdmClose (); return -1; } if ((ver & 0xff00) != (BDM_DRV_VERSION & 0xff00)) { bdmIO_lastErrorString = "invalid driver version"; bdmClose (); return -1; } #endif /* * Get the processor and interface type */ if (bdmGetProcessor (&cpu) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); bdmClose (); return -1; } if (bdmGetInterface (&iface) < 0) { bdmIO_lastErrorString = bdmStrerror (errno); bdmClose (); return -1; } return bdm_fd; } /* * Close the specified BDM device */ int bdmClose (void) { if (config) { free (config); config = NULL; config_buffer_size = 0; } if (!bdmCheck ()) return -1; #if defined (BDM_DEVICE_REMOTE) if (bdmRemote) { bdmRemote = 0; if (bdmRemoteClose (bdm_fd) < 0) { bdm_fd = -1; return -1; } } else { #endif #if defined (BDM_DEVICE_LOCAL) if (close (bdm_fd) < 0) { bdm_fd = -1; bdmIO_lastErrorString = bdmStrerror (errno); return -1; } #endif #if defined (BDM_DEVICE_REMOTE) } #endif bdm_fd = -1; return 0; } /* * Tell if interface is open */ int bdmIsOpen (void) { return (bdm_fd >= 0); } /* * Return the status of the BDM interface */ int bdmStatus (void) { int status = 0; if (bdmIoctlInt (BDM_GET_STATUS, &status) < 0) return -1; PRINTF ("Status %#x\n", status); return status; } /* * Set the delay time */ int bdmSetDelay (int delay) { if (bdmIoctlInt (BDM_SPEED, &delay) < 0) return -1; PRINTF ("Set delay %d\n", delay); return 0; } /* * Set the driver debug flag */ int bdmSetDriverDebugFlag (int debugFlag) { if (bdmIoctlInt (BDM_DEBUG, &debugFlag) < 0) return -1; PRINTF ("Set driver debug flag %d\n", debugFlag); return 0; } /* * Get the Coldfire PST enable state. */ int bdmColdfireGetPST (int *pst) { if (bdmIoctlInt (BDM_GET_CF_PST, pst) < 0) return -1; PRINTF ("Get Coldfire PST state: %d\n", *pst); return 0; } /* * Set the Coldfire PST enable state. */ int bdmColdfireSetPST (int pst) { if (bdmIoctlInt (BDM_SET_CF_PST, &pst) < 0) return -1; PRINTF ("Set Coldfire PST state: %d\n", pst); return 0; } /* * Read a control register */ int bdmReadControlRegister (int code, unsigned long *lp) { unsigned long ltmp = 0; if (readTarget (BDM_READ_CTLREG, code, <mp) < 0) return -1; PRINTF ("Read control register 0x%04x: %#8lx\n", code, ltmp); *lp = ltmp; return 0; } /* * Read a debug register */ int bdmReadDebugRegister (int code, unsigned long *lp) { unsigned long ltmp = 0; if (readTarget (BDM_READ_DBREG, code, <mp) < 0) return -1; PRINTF ("Read debug register 0x%04x: %#8lx\n", code, ltmp); *lp = ltmp; return 0; } /* * Read a system register */ int bdmReadSystemRegister (int code, unsigned long *lp) { unsigned long ltmp = 0; if (readTarget (BDM_READ_SYSREG, code, <mp) < 0) return -1; PRINTF ("Read system register %s: %#8lx\n", sysregName[code], ltmp); *lp = ltmp; return 0; } /* * Read a register */ int bdmReadRegister (int code, unsigned long *lp) { unsigned long ltmp = 0; code &= 0xF; if (readTarget (BDM_READ_REG, code, <mp) < 0) return -1; PRINTF ("Read register %s: %#8lx\n", regName[code], ltmp); *lp = ltmp; return 0; } /* * Write a control register */ int bdmWriteControlRegister (int code, unsigned long l) { if (writeTarget (BDM_WRITE_CTLREG, code, l) < 0) return -1; PRINTF ("Write control register 0x%04x: %#8lx\n", code, l); return 0; } /* * Write a debug register */ int bdmWriteDebugRegister (int code, unsigned long l) { if (writeTarget (BDM_WRITE_DBREG, code, l) < 0) return -1; PRINTF ("Write debug register 0x%04x: %#8lx\n", code, l); return 0; } /* * Write a system register */ int bdmWriteSystemRegister (int code, unsigned long l) { if (writeTarget (BDM_WRITE_SYSREG, code, l) < 0) return -1; PRINTF ("Write system register %s: %#8lx\n", sysregName[code], l); return 0; } /* * Write a register */ int bdmWriteRegister (int code, unsigned long l) { if (writeTarget (BDM_WRITE_REG, code, l) < 0) return -1; PRINTF ("Write register %s: %#8lx\n", regName[code], l); return 0; } /* * Read a long word */ int bdmReadLongWord (unsigned long address, unsigned long *lp) { unsigned long ltmp; if (readTarget (BDM_READ_LONGWORD, address, <mp) < 0) return -1; PRINTF ("Read %#8.8lx @ %#8lx\n", ltmp, address); *lp = ltmp; return 0; } /* * Read a word */ int bdmReadWord (unsigned long address, unsigned short *sp) { unsigned long ltmp; if (readTarget (BDM_READ_WORD, address, <mp) < 0) return -1; *sp = ltmp; PRINTF ("Read %#4.4x @ %#8lx\n", (unsigned short) ltmp, address); return 0; } /* * Read a byte */ int bdmReadByte (unsigned long address, unsigned char *cp) { unsigned long ltmp; if (readTarget (BDM_READ_BYTE, address, <mp) < 0) return -1; *cp = ltmp; PRINTF ("Read %#2.2x @ %#8lx\n", (unsigned char)ltmp, address); return 0; } /* * Write a long word */ int bdmWriteLongWord (unsigned long address, unsigned long l) { PRINTF ("Write %#8.8lx @ %#8lx\n", l, address); return writeTarget (BDM_WRITE_LONGWORD, address, l); } /* * Write a word */ int bdmWriteWord (unsigned long address, unsigned short s) { PRINTF ("Write %#4.4x @ %#8lx\n", s, address); return writeTarget (BDM_WRITE_WORD, address, s); } /* * Write a byte */ int bdmWriteByte (unsigned long address, unsigned char c) { PRINTF ("Write %#2.2x @ %#8lx\n", c, address); return writeTarget (BDM_WRITE_BYTE, address, c); } /* * Read the Module Base Address Register */ int bdmReadMBAR (unsigned long *lp) { return bdmReadSystemRegister (BDM_REG_MBAR, lp); } /* * Write the Module Base Address Register */ int bdmWriteMBAR (unsigned long l) { return bdmWriteSystemRegister (BDM_REG_MBAR, l); } /* * Reset the target and disable BDM operation */ int bdmRelease (void) { PRINTF ("Release\n"); return bdmIoctlCommand (BDM_RELEASE_CHIP); } /* * Reset the target, enable BDM operation, enter BDM */ int bdmReset (void) { PRINTF ("Reset\n"); return bdmIoctlCommand (BDM_RESET_CHIP); } /* * Restart the chip. */ int bdmRestart (void) { PRINTF ("Restart\n"); return bdmIoctlCommand (BDM_RESTART_CHIP); } /* * Restart target execution */ int bdmGo (void) { PRINTF ("Go\n"); return bdmIoctlCommand (BDM_GO); } /* * Stop the target */ int bdmStop (void) { PRINTF ("Stop\n"); return bdmIoctlCommand (BDM_STOP_CHIP); } /* * Single-step the target */ int bdmStep (void) { PRINTF ("Step\n"); return bdmIoctlCommand (BDM_STEP_CHIP); } /* * Read target memory * `cbuf' is in target byte order */ int bdmReadMemory (unsigned long address, unsigned char *cbuf, unsigned long nbytes) { if (nbytes == 0) return 0; if (!bdmCheck ()) return -1; /* * Transfer first part and set up target address pointer */ if (((address & 0x3) == 0) && (nbytes >= 4)) { unsigned long l; if (bdmReadLongWord (address, &l) < 0) return -1; *cbuf++ = l >> 24; *cbuf++ = l >> 16; *cbuf++ = l >> 8; *cbuf++ = l; address += 4; nbytes -= 4; } else if (((address & 0x1) == 0) && (nbytes >= 2)) { unsigned short s; if (bdmReadWord (address, &s) < 0) return -1; *cbuf++ = s >> 8; *cbuf++ = s; address += 2; nbytes -= 2; } else { do { if (bdmReadByte (address, cbuf) < 0) return -1; cbuf++; address++; nbytes--; } while (nbytes && (address & 0x3)); } if (nbytes == 0) return 0; if (bdmRead (cbuf, nbytes) < 0) return -1; PRINTF ("Read %d byte%s\n", nbytes, nbytes == 1 ? "" : "s"); return 0; } /* * Write target memory * `cbuf' is in target byte order */ int bdmWriteMemory (unsigned long address, unsigned char *cbuf, unsigned long nbytes) { int ret; if (nbytes == 0) return 0; if (!bdmCheck ()) return -1; /* * Transfer first part and set up target address pointer */ if (((address & 0x3) == 0) && (nbytes >= 4)) { unsigned long l; l = (unsigned long)*cbuf++ << 24; l |= (unsigned long)*cbuf++ << 16; l |= (unsigned long)*cbuf++ << 8; l |= (unsigned long)*cbuf++; if (bdmWriteLongWord (address, l) < 0) return -1; address += 4; nbytes -= 4; } else if (((address & 0x1) == 0) && (nbytes >= 2)) { unsigned short s; s = (unsigned short)*cbuf++ << 8; s |= (unsigned short)*cbuf++; if (bdmWriteWord (address, s) < 0) return -1; address += 2; nbytes -= 2; } else { do { if (bdmWriteByte (address, *cbuf) < 0) return -1; cbuf++; address++; nbytes--; } while (nbytes && (address & 0x3)); } if (nbytes == 0) return 0; ret = bdmWrite (cbuf, nbytes); if (ret < 0) return -1; PRINTF ("Wrote %d byte%s\n", nbytes, nbytes == 1 ? "" : "s"); return 0; } /* * Get Driver version */ int bdmGetDrvVersion (unsigned int *ver) { if (bdmIoctlInt (BDM_GET_DRV_VER, (int*) ver) < 0) return -1; PRINTF ("Driver version: %d.%d\n", *ver >> 8, *ver & 0xff); return 0; } /* * Get Processor type */ int bdmGetProcessor (int *processor) { if (bdmIoctlInt (BDM_GET_CPU_TYPE, processor) < 0) return -1; PRINTF ("CPU type: %d\n", *processor); return 0; } /* * Get Interface type */ int bdmGetInterface (int *iface) { if (bdmIoctlInt (BDM_GET_IF_TYPE, iface) < 0) return -1; PRINTF ("Interface type: %d\n", *iface); return 0; }