1393 lines
34 KiB
C
1393 lines
34 KiB
C
/*
|
|
* Motorola Background Debug Mode Driver
|
|
* Copyright (C) 1995 W. Eric Norum
|
|
* Copyright (C) 1998-2007 Chris Johns
|
|
*
|
|
* Based on:
|
|
* 1. `A Background Debug Mode Driver Package for Motorola's
|
|
* 16- and 32-Bit Microcontrollers', Scott Howard, Motorola
|
|
* Canada, 1993.
|
|
* 2. `Linux device driver for public domain BDM Interface',
|
|
* M. Schraut, Technische Universitaet Muenchen, Lehrstuhl
|
|
* fuer Prozessrechner, 1995.
|
|
*
|
|
* Extended to support the ColdFire BDM interface using the P&E
|
|
* module which comes with the EVB. Currently only tested with the
|
|
* 5206 (5V) device.
|
|
*
|
|
* 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
|
|
* chris@users.sourceforge.net
|
|
*
|
|
* ccj@acm.org
|
|
*
|
|
* 19/1/1999 -- Greg Ungerer (gerg@moreton.com.au)
|
|
* Added support for more recent LINUX kernels 2.2.0+
|
|
*
|
|
* 22/10/1999 -- CCJ (ccj@acm.org)
|
|
* Remove the OS specific parts to allow for easier support for
|
|
* different OS's. This is based on the work done by
|
|
* David McCullough (davidm@stallion.oz.au) for the SCO port.
|
|
*
|
|
* 31/05/2000 - CCJ (ccj@acm.org)
|
|
* Merged in the ICD interface, and renamed the Eric interface
|
|
* to the PD interface.
|
|
*
|
|
* 01/09/2000 - ASA (aaganichev@hypercom.com)
|
|
* Fixed ICD and PD support basing on original driver code, fix ICD name
|
|
* misspelling.
|
|
*
|
|
* 14/11/2000 - James Housley <jim@thehousleys.net>
|
|
* Greg Tunnock (gtunnock@redfernnetworks.com)
|
|
* Port to FreeBSD.
|
|
*
|
|
* 02/02/2001 - KJO (vac4050@cae597.rsc.raytheon.com)
|
|
* Reduced time delays in some cpu32_icd_xxx() functions to improve
|
|
* performance of cpu32 ICD driver and speed up downloads.
|
|
*
|
|
* 12/12/2001 - Thomas Andrew (tandrews@mindspring.co.za)
|
|
* Change to stop getting "Invalid instruction (0x1FFFF) back from the
|
|
* ICD interface.
|
|
*/
|
|
|
|
/*
|
|
* Declarations common to kernel and user code
|
|
*/
|
|
#include "bdm.h"
|
|
|
|
/*
|
|
************************************************************************
|
|
* BDM driver control structure *
|
|
************************************************************************
|
|
*/
|
|
|
|
struct BDM {
|
|
/*
|
|
* Device name, processor and interface type
|
|
*/
|
|
char name[20];
|
|
int processor;
|
|
int interface;
|
|
|
|
/*
|
|
* Device I/O ports
|
|
*/
|
|
int exists;
|
|
int portsAreMine;
|
|
int portBase;
|
|
int dataPort;
|
|
int statusPort;
|
|
int controlPort;
|
|
int usbDev;
|
|
|
|
/*
|
|
* Control debugging messages
|
|
*/
|
|
int debugFlag;
|
|
|
|
/*
|
|
* Device is exclusive-use
|
|
*/
|
|
int isOpen;
|
|
|
|
/*
|
|
* Serial I/O delay timer
|
|
*/
|
|
int delayTimer;
|
|
|
|
/*
|
|
* I/O buffer
|
|
*/
|
|
char ioBuffer[512];
|
|
unsigned int readValue;
|
|
|
|
/*
|
|
* Interface specific handlers
|
|
*/
|
|
int (*get_status)(struct BDM *self);
|
|
int (*init_hardware) (struct BDM *self);
|
|
int (*serial_clock) (struct BDM *self, unsigned short wval, int holdback);
|
|
int (*gen_bus_error) (struct BDM *self);
|
|
int (*restart_chip) (struct BDM *self);
|
|
int (*release_chip) (struct BDM *self);
|
|
int (*reset_chip) (struct BDM *self);
|
|
int (*stop_chip) (struct BDM *self);
|
|
int (*run_chip) (struct BDM *self);
|
|
int (*step_chip) (struct BDM *self);
|
|
int (*fill_buf) (struct BDM *self, int count);
|
|
int (*send_buf) (struct BDM *self, int count);
|
|
int (*read_sysreg) (struct BDM *self, struct BDMioctl *ioc, int mode);
|
|
int (*read_proreg) (struct BDM *self, struct BDMioctl *ioc);
|
|
int (*read_long_word) (struct BDM *self, struct BDMioctl *ioc);
|
|
int (*read_word) (struct BDM *self, struct BDMioctl *ioc);
|
|
int (*read_byte) (struct BDM *self, struct BDMioctl *ioc);
|
|
int (*write_sysreg) (struct BDM *self, struct BDMioctl *ioc, int mode);
|
|
int (*write_proreg) (struct BDM *self, struct BDMioctl *ioc);
|
|
int (*write_long_word) (struct BDM *self, struct BDMioctl *ioc);
|
|
int (*write_word) (struct BDM *self, struct BDMioctl *ioc);
|
|
int (*write_byte) (struct BDM *self, struct BDMioctl *ioc);
|
|
|
|
/*
|
|
* Some system registers are write only so we need to shadow them
|
|
*/
|
|
unsigned long shadow_sysreg[BDM_MAX_SYSREG];
|
|
|
|
/*
|
|
* Coldfire processors have different versions of the debug module.
|
|
* These also require special operations to occur.
|
|
*/
|
|
int cf_debug_ver;
|
|
int cf_use_pst;
|
|
|
|
/*
|
|
* Need to get the status from the csr, how-ever the status bits are a
|
|
* once read then clear so we need logic to store this state to know
|
|
* the status.
|
|
*/
|
|
int cf_running;
|
|
unsigned long cf_csr;
|
|
|
|
/*
|
|
* Revision D BDM hardware does not have a bit to mask interrupts so
|
|
* we must save the SR when we step and then restore when we go.
|
|
*/
|
|
unsigned long cf_sr_mask_cache;
|
|
int cf_sr_masked;
|
|
|
|
/*
|
|
* Address for the current transfer. The TBLCF pod always
|
|
* takes the address rather than streaming. This should be changed.
|
|
*/
|
|
unsigned long address;
|
|
|
|
#ifdef BDM_BIT_BASH_PORT
|
|
|
|
int (*bit_bash) (struct BDM *self, unsigned short mask, unsigned short value);
|
|
|
|
/*
|
|
* The current state of the bit bash bits. Easier than figuring out
|
|
* if the bit should be on or off by reading the PC port. I am sure
|
|
* this could be done, but I am not a PC parallel port expert.
|
|
*/
|
|
|
|
unsigned short bit_bash_bits;
|
|
|
|
#endif
|
|
};
|
|
|
|
/*
|
|
************************************************************************
|
|
* System Register Modes *
|
|
************************************************************************
|
|
*/
|
|
#define BDM_SYS_REG_MODE_MAPPED (0)
|
|
#define BDM_SYS_REG_MODE_CONTROL (1)
|
|
#define BDM_SYS_REG_MODE_DEBUG (2)
|
|
|
|
/*
|
|
************************************************************************
|
|
* Common Functions *
|
|
************************************************************************
|
|
*/
|
|
|
|
static int bdmDrvGetStatus (struct BDM *self);
|
|
static int bdmDrvInitHardware (struct BDM *self);
|
|
static int bdmDrvRestartChip (struct BDM *self);
|
|
static int bdmDrvReleaseChip (struct BDM *self);
|
|
static int bdmDrvResetChip (struct BDM *self);
|
|
static int bdmDrvStopChip (struct BDM *self);
|
|
static int bdmDrvSerialClock (struct BDM *self, unsigned short wval, int holdback);
|
|
static int bdmDrvGenerateBusError (struct BDM *self);
|
|
static int bdmDrvStepChip (struct BDM *self);
|
|
static int bdmDrvSendCommandTillTargetReady (struct BDM *self,
|
|
unsigned short command);
|
|
static int bdmDrvFillBuf (struct BDM *self, int count);
|
|
static int bdmDrvSendBuf (struct BDM *self, int count);
|
|
static int bdmDrvGo (struct BDM *self);
|
|
static int bdmDrvReadSystemRegister (struct BDM *self, struct BDMioctl *ioc, int mode);
|
|
static int bdmDrvReadProcessorRegister (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmDrvReadLongWord (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmDrvReadWord (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmDrvReadByte (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmDrvWriteSystemRegister (struct BDM *self, struct BDMioctl *ioc, int mode);
|
|
static int bdmDrvWriteProcessorRegister (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmDrvWriteLongWord (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmDrvWriteWord (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmDrvWriteByte (struct BDM *self, struct BDMioctl *ioc);
|
|
|
|
/*
|
|
* Common processor defines.
|
|
*/
|
|
|
|
/*
|
|
* CPU Generated Messages.
|
|
*/
|
|
|
|
#define CGM_FAILURE 1 /* bit 16, s/c bit */
|
|
#define CGM_CMD_OK 0xffff
|
|
#define CGM_NOT_READY 0x0000
|
|
#define CGM_BUS_ERROR 0x0001
|
|
#define CGM_ILLEGAL_CMD 0xffff
|
|
|
|
/*
|
|
* Command codes for BDM interface
|
|
*/
|
|
|
|
#define BDM_RREG_CMD 0x2180 /* CPU32, Coldfire */
|
|
#define BDM_WREG_CMD 0x2080 /* CPU32, Coldfire */
|
|
#define BDM_RSREG_CMD 0x2580 /* CPU32, Coldfire */
|
|
#define BDM_WSREG_CMD 0x2480 /* CPU32, Coldfire */
|
|
#define BDM_READ_CMD 0x1900 /* CPU32, Coldfire */
|
|
#define BDM_WRITE_CMD 0x1800 /* CPU32, Coldfire */
|
|
#define BDM_DUMP_CMD 0x1d00 /* CPU32, Coldfire */
|
|
#define BDM_FILL_CMD 0x1c00 /* CPU32, Coldfire */
|
|
#define BDM_GO_CMD 0x0c00 /* CPU32, Coldfire */
|
|
#define BDM_CALL_CMD 0x0800 /* CPU32 */
|
|
#define BDM_RST_CMD 0x0400 /* CPU32, Coldfire */
|
|
#define BDM_NOP_CMD 0x0000 /* CPU32, Coldfire */
|
|
#define BDM_RCREG_CMD 0x2980 /* Coldfire */
|
|
#define BDM_WCREG_CMD 0x2880 /* Coldfire */
|
|
#define BDM_RDMREG_CMD 0x2d80 /* Coldfire */
|
|
#define BDM_WDMREG_CMD 0x2c80 /* Coldfire */
|
|
#define BDM_FORCED_TA_CMD 0x0002 /* Coldfire version D and higher */
|
|
|
|
/*
|
|
* Operand size for BDM_READ_CMD/BDM_WRITE_CMD
|
|
*/
|
|
|
|
#define BDM_SIZE_BYTE 0x0000
|
|
#define BDM_SIZE_WORD 0x0040
|
|
#define BDM_SIZE_LONG 0x0080
|
|
|
|
/*
|
|
* Address/Data field
|
|
*/
|
|
|
|
#define BDM_ADDR_NOT_DATA 0x0004
|
|
|
|
/*
|
|
* Per-device data.
|
|
* Allocate a struct for each port for each interface.
|
|
*/
|
|
static struct BDM bdm_device_info[BDM_NUM_OF_MINORS];
|
|
|
|
/*
|
|
* Does this host require swapping.
|
|
*/
|
|
static int mustSwap;
|
|
|
|
/*
|
|
************************************************************************
|
|
* Genric Bit Bash Functions Decls *
|
|
************************************************************************
|
|
*/
|
|
|
|
static int bdmBitBashSendCommandTillTargetReady (struct BDM *self,
|
|
unsigned short command);
|
|
static int bdmBitBashFillBuf (struct BDM *self, int count);
|
|
static int bdmBitBashSendBuf (struct BDM *self, int count);
|
|
static int bdmbitBashFetchWord (struct BDM *self, unsigned short *sp);
|
|
static int bdmBitBashReadProcessorRegister (struct BDM *self,
|
|
struct BDMioctl *ioc);
|
|
static int bdmBitBashReadLongWord (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmBitBashReadWord (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmBitBashReadByte (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmBitBashWriteProcessorRegister (struct BDM *self,
|
|
struct BDMioctl *ioc);
|
|
static int bdmBitBashWriteLongWord (struct BDM *self,
|
|
struct BDMioctl *ioc);
|
|
static int bdmBitBashWriteWord (struct BDM *self, struct BDMioctl *ioc);
|
|
static int bdmBitBashWriteByte (struct BDM *self, struct BDMioctl *ioc);
|
|
|
|
|
|
/*
|
|
************************************************************************
|
|
* CPU32 for PD/ICD interface support routines *
|
|
************************************************************************
|
|
*/
|
|
|
|
#include "bdm-cpu32.c"
|
|
|
|
/*
|
|
************************************************************************
|
|
* Coldfire P&E support routines *
|
|
************************************************************************
|
|
*/
|
|
|
|
#include "bdm-cf-pe.c"
|
|
|
|
/*
|
|
************************************************************************
|
|
* Coldfire P&E support routines *
|
|
************************************************************************
|
|
*/
|
|
|
|
#if BDM_TBLCF_USB
|
|
#include "bdm-tblcf.c"
|
|
#endif
|
|
|
|
/*
|
|
************************************************************************
|
|
* Genric Bit Bash Functions *
|
|
************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Loop till target I/O operation completes
|
|
*/
|
|
static int
|
|
bdmBitBashSendCommandTillTargetReady (struct BDM *self, unsigned short command)
|
|
{
|
|
int err;
|
|
int timeout = 0;
|
|
|
|
/*
|
|
* If no response is returned hit the bus error line and
|
|
* then wait for the bus error response.
|
|
*/
|
|
for (;;) {
|
|
err = bdmDrvSerialClock (self, command, 0);
|
|
if (err)
|
|
return err;
|
|
if ((self->readValue & 0x10000) == 0)
|
|
return 0;
|
|
++timeout;
|
|
if (timeout == 5) {
|
|
/*
|
|
* Should get a bus error response back.
|
|
*/
|
|
bdmDrvGenerateBusError (self);
|
|
}
|
|
if (timeout > 6) {
|
|
return BDM_FAULT_RESPONSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Fill I/O buffer with data from target
|
|
*/
|
|
static int
|
|
bdmBitBashFillBuf (struct BDM *self, int count)
|
|
{
|
|
unsigned short *sp = (unsigned short *)self->ioBuffer;
|
|
int cmd;
|
|
int err;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashFillBuf - count:%d\n", count);
|
|
|
|
if (count == 0)
|
|
return 0;
|
|
|
|
if (count >= 4)
|
|
cmd = BDM_DUMP_CMD | BDM_SIZE_LONG;
|
|
else if (count >= 2)
|
|
cmd = BDM_DUMP_CMD | BDM_SIZE_WORD;
|
|
else
|
|
cmd = BDM_DUMP_CMD | BDM_SIZE_BYTE;
|
|
|
|
err = bdmDrvSerialClock (self, cmd, 0);
|
|
if (err)
|
|
return err;
|
|
|
|
for (;;) {
|
|
switch (count) {
|
|
case 1:
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
|
|
if (err)
|
|
return err;
|
|
*(unsigned char *)sp = self->readValue;
|
|
return 0;
|
|
|
|
case 2:
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
|
|
if (err)
|
|
return err;
|
|
*sp = self->readValue;
|
|
return 0;
|
|
|
|
case 3:
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_DUMP_CMD | BDM_SIZE_BYTE);
|
|
if (err)
|
|
return err;
|
|
*sp++ = self->readValue;
|
|
count -= 2;
|
|
break;
|
|
|
|
case 4:
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
|
|
if (err)
|
|
return err;
|
|
*sp++ = self->readValue;
|
|
err = bdmDrvSerialClock (self, BDM_NOP_CMD, 0);
|
|
if (err)
|
|
return err;
|
|
*sp = self->readValue;
|
|
return 0;
|
|
|
|
case 5:
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
|
|
if (err)
|
|
return err;
|
|
*sp++ = self->readValue;
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_DUMP_CMD | BDM_SIZE_BYTE);
|
|
if (err)
|
|
return err;
|
|
*sp++ = self->readValue;
|
|
count -= 4;
|
|
break;
|
|
|
|
case 6:
|
|
case 7:
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
|
|
if (err)
|
|
return err;
|
|
*sp++ = self->readValue;
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_DUMP_CMD | BDM_SIZE_WORD);
|
|
if (err)
|
|
return err;
|
|
*sp++ = self->readValue;
|
|
count -= 4;
|
|
break;
|
|
|
|
default:
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
|
|
if (err)
|
|
return err;
|
|
*sp++ = self->readValue;
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_DUMP_CMD | BDM_SIZE_LONG);
|
|
if (err)
|
|
return err;
|
|
*sp++ = self->readValue;
|
|
count -= 4;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Send contents of I/O buffer to target
|
|
*/
|
|
static int
|
|
bdmBitBashSendBuf (struct BDM *self, int count)
|
|
{
|
|
unsigned short *sp = (unsigned short *)self->ioBuffer;
|
|
int cmd;
|
|
int err;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashSendBuf - count:%d\n", count);
|
|
|
|
if (count == 0)
|
|
return 0;
|
|
|
|
for (;;) {
|
|
if (count >= 4)
|
|
cmd = BDM_FILL_CMD | BDM_SIZE_LONG;
|
|
else if (count >= 2)
|
|
cmd = BDM_FILL_CMD | BDM_SIZE_WORD;
|
|
else if (count >= 1)
|
|
cmd = BDM_FILL_CMD | BDM_SIZE_BYTE;
|
|
else
|
|
cmd = BDM_NOP_CMD;
|
|
err = bdmBitBashSendCommandTillTargetReady (self, cmd);
|
|
if (err)
|
|
return err;
|
|
if (count >= 4) {
|
|
err = bdmDrvSerialClock (self, *sp++, 0);
|
|
if (err)
|
|
return err;
|
|
err = bdmDrvSerialClock (self, *sp++, 0);
|
|
if (err)
|
|
return err;
|
|
count -= 4;
|
|
}
|
|
else if (count >= 2) {
|
|
err = bdmDrvSerialClock (self, *sp++, 0);
|
|
if (err)
|
|
return err;
|
|
count -= 2;
|
|
}
|
|
else if (count >= 1) {
|
|
err = bdmDrvSerialClock (self, *(unsigned char *)sp, 0);
|
|
if (err)
|
|
return err;
|
|
count -= 1;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get a word from the target
|
|
*/
|
|
int
|
|
bdmBitBashFetchWord (struct BDM *self, unsigned short *sp)
|
|
{
|
|
int err;
|
|
|
|
err = bdmBitBashSendCommandTillTargetReady (self, BDM_NOP_CMD);
|
|
if (err)
|
|
return err;
|
|
*sp = self->readValue;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read processor register
|
|
*/
|
|
static int
|
|
bdmBitBashReadProcessorRegister (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
int err;
|
|
unsigned short msw, lsw;
|
|
|
|
if (((err = bdmDrvSerialClock (self, BDM_RREG_CMD | (ioc->address & 0xF), 0)) != 0) ||
|
|
((err = bdmBitBashFetchWord (self, &msw)) != 0) ||
|
|
((err = bdmBitBashFetchWord (self, &lsw)) != 0)) {
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashReadProcessorRegister - reg:0x%02x, failed err=%d\n",
|
|
ioc->address & 0xF, err);
|
|
return err;
|
|
}
|
|
|
|
ioc->value = (msw << 16) | lsw;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashReadProcessorRegister - reg:0x%02x = 0x%08x\n",
|
|
ioc->address & 0xF, ioc->value);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a long word from memory
|
|
*/
|
|
static int
|
|
bdmBitBashReadLongWord (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
int err;
|
|
unsigned short msw, lsw;
|
|
|
|
if (((err = bdmDrvSerialClock (self, BDM_READ_CMD | BDM_SIZE_LONG, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
|
|
((err = bdmBitBashFetchWord (self, &msw)) != 0) ||
|
|
((err = bdmBitBashFetchWord (self, &lsw)) != 0)) {
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashReadLongWord : *0x%08x failed, err=%d\n", ioc->address, err);
|
|
return err;
|
|
}
|
|
|
|
ioc->value = (msw << 16) | lsw;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashReadLongWord : *0x%08x = 0x%08x\n", ioc->address, ioc->value);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a word from memory
|
|
*/
|
|
static int
|
|
bdmBitBashReadWord (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
int err;
|
|
unsigned short w;
|
|
|
|
if (((err = bdmDrvSerialClock (self, BDM_READ_CMD | BDM_SIZE_WORD, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
|
|
((err = bdmBitBashFetchWord (self, &w)) != 0)) {
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashReadWord : *0x%08x failed, err=%d\n", ioc->address, err);
|
|
return err;
|
|
}
|
|
|
|
ioc->value = w;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashReadWord : *0x%08x = 0x%04x\n", ioc->address, (ioc->value & 0xffff));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a byte from memory
|
|
*/
|
|
static int
|
|
bdmBitBashReadByte (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
int err;
|
|
unsigned short w;
|
|
|
|
if (((err = bdmDrvSerialClock (self, BDM_READ_CMD | BDM_SIZE_BYTE, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
|
|
((err = bdmBitBashFetchWord (self, &w)) != 0)){
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashReadByte : *0x%08x failed, err=%d\n", ioc->address, err);
|
|
|
|
return err;
|
|
}
|
|
|
|
ioc->value = w;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashReadByte : *0x%08x = 0x%02x\n", ioc->address, (ioc->value & 0xff));
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write processor register
|
|
*/
|
|
static int
|
|
bdmBitBashWriteProcessorRegister (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
int err;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashWriteProcessorRegister - reg:%d, val:0x%08x\n",
|
|
ioc->address & 0xF, ioc->value);
|
|
|
|
if (((err = bdmDrvSerialClock (self, BDM_WREG_CMD | (ioc->address & 0xF), 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->value >> 16, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->value, 0)) != 0))
|
|
return err;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a long word to memory
|
|
*/
|
|
static int
|
|
bdmBitBashWriteLongWord (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
int err;
|
|
unsigned short w;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashWriteLongWord : 0x%08x = 0x%08x\n", ioc->address, ioc->value);
|
|
|
|
if (((err = bdmDrvSerialClock (self, BDM_WRITE_CMD | BDM_SIZE_LONG, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->value >> 16, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->value, 0)) != 0) ||
|
|
((err = bdmBitBashFetchWord (self, &w)) != 0))
|
|
return err;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a word to memory
|
|
*/
|
|
static int
|
|
bdmBitBashWriteWord (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
int err;
|
|
unsigned short w;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashWriteWord : 0x%08x = 0x%04x\n", ioc->address, (ioc->value & 0xffff));
|
|
|
|
if (((err = bdmDrvSerialClock (self, BDM_WRITE_CMD | BDM_SIZE_WORD, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->value, 0)) != 0) ||
|
|
((err = bdmBitBashFetchWord (self, &w)) != 0))
|
|
return err;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a byte to memory
|
|
*/
|
|
static int
|
|
bdmBitBashWriteByte (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
int err;
|
|
unsigned short w;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdmBitBashWriteByte : 0x%08x = 0x%02x\n", ioc->address, (ioc->value & 0xff));
|
|
|
|
if (((err = bdmDrvSerialClock (self, BDM_WRITE_CMD | BDM_SIZE_BYTE, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address >> 16, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->address, 0)) != 0) ||
|
|
((err = bdmDrvSerialClock (self, ioc->value, 0)) != 0) ||
|
|
((err = bdmBitBashFetchWord (self, &w)) != 0))
|
|
return err;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
************************************************************************
|
|
* Common Functions *
|
|
************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Get target status
|
|
*/
|
|
static int
|
|
bdmDrvGetStatus (struct BDM *self)
|
|
{
|
|
return (self->get_status) (self);
|
|
}
|
|
|
|
/*
|
|
* Hardware initialization
|
|
*/
|
|
static int
|
|
bdmDrvInitHardware (struct BDM *self)
|
|
{
|
|
return (self->init_hardware) (self);
|
|
}
|
|
|
|
/*
|
|
* Clock a word to/from the target
|
|
*/
|
|
static int
|
|
bdmDrvSerialClock (struct BDM *self, unsigned short wval, int holdback)
|
|
{
|
|
return (self->serial_clock) (self, wval, holdback);
|
|
}
|
|
|
|
/*
|
|
* Generate a bus error on the target.
|
|
*/
|
|
static int
|
|
bdmDrvGenerateBusError (struct BDM *self)
|
|
{
|
|
return (self->gen_bus_error) (self);
|
|
}
|
|
|
|
/*
|
|
* Restart chip and stop on the first instruction fetch
|
|
*/
|
|
static int
|
|
bdmDrvRestartChip (struct BDM *self)
|
|
{
|
|
return (self->restart_chip) (self);
|
|
}
|
|
|
|
/*
|
|
* Restart chip and disable background debugging mode
|
|
*/
|
|
static int
|
|
bdmDrvReleaseChip (struct BDM *self)
|
|
{
|
|
return (self->release_chip) (self);
|
|
}
|
|
|
|
/*
|
|
* Reset chip, enable background debugging mode, halt on first fetch.
|
|
*
|
|
*/
|
|
static int
|
|
bdmDrvResetChip (struct BDM *self)
|
|
{
|
|
return (self->reset_chip) (self);
|
|
}
|
|
|
|
/*
|
|
* Force the target into background debugging mode
|
|
*/
|
|
static int
|
|
bdmDrvStopChip (struct BDM *self)
|
|
{
|
|
return (self->stop_chip) (self);
|
|
}
|
|
|
|
/*
|
|
* Restart target execution
|
|
*/
|
|
static int
|
|
bdmDrvGo (struct BDM *self)
|
|
{
|
|
return (self->run_chip) (self);
|
|
}
|
|
|
|
/*
|
|
* Make the target execute a single instruction and
|
|
* reenter background debugging mode
|
|
*/
|
|
static int
|
|
bdmDrvStepChip (struct BDM *self)
|
|
{
|
|
return (self->step_chip) (self);
|
|
}
|
|
|
|
/*
|
|
* Fill I/O buffer with data from target
|
|
*/
|
|
static int
|
|
bdmDrvFillBuf (struct BDM *self, int count)
|
|
{
|
|
int err = (self->fill_buf) (self, count);
|
|
if (mustSwap)
|
|
{
|
|
char *p = self->ioBuffer;
|
|
int i;
|
|
char c;
|
|
for (i = 0; i < (count - 1); i += 2)
|
|
{
|
|
c = *p;
|
|
*p = *(p + 1);
|
|
p++;
|
|
*p = c;
|
|
p++;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Send contents of I/O buffer to target
|
|
*/
|
|
static int
|
|
bdmDrvSendBuf (struct BDM *self, int count)
|
|
{
|
|
if (mustSwap)
|
|
{
|
|
char *p = self->ioBuffer;
|
|
int i;
|
|
char c;
|
|
for (i = 0; i < (count - 1); i += 2)
|
|
{
|
|
c = *p;
|
|
*p = *(p + 1);
|
|
p++;
|
|
*p = c;
|
|
p++;
|
|
}
|
|
}
|
|
return (self->send_buf) (self, count);
|
|
}
|
|
|
|
/*
|
|
* Read system register
|
|
*/
|
|
static int
|
|
bdmDrvReadSystemRegister (struct BDM *self, struct BDMioctl *ioc, int mode)
|
|
{
|
|
return (self->read_sysreg) (self, ioc, mode);
|
|
}
|
|
|
|
/*
|
|
* Read processor register
|
|
*/
|
|
static int
|
|
bdmDrvReadProcessorRegister (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
return (self->read_proreg) (self, ioc);
|
|
}
|
|
|
|
/*
|
|
* Read a long word from memory
|
|
*/
|
|
static int
|
|
bdmDrvReadLongWord (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
return (self->read_long_word) (self, ioc);
|
|
}
|
|
|
|
/*
|
|
* Read a word from memory
|
|
*/
|
|
static int
|
|
bdmDrvReadWord (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
return (self->read_word) (self, ioc);
|
|
}
|
|
|
|
/*
|
|
* Read a byte from memory
|
|
*/
|
|
static int
|
|
bdmDrvReadByte (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
return (self->read_byte) (self, ioc);
|
|
}
|
|
|
|
/*
|
|
* Write system register
|
|
*/
|
|
static int
|
|
bdmDrvWriteSystemRegister (struct BDM *self, struct BDMioctl *ioc, int mode)
|
|
{
|
|
return (self->write_sysreg) (self, ioc, mode);
|
|
}
|
|
|
|
/*
|
|
* Write processor register
|
|
*/
|
|
static int
|
|
bdmDrvWriteProcessorRegister (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
return (self->write_proreg) (self, ioc);
|
|
}
|
|
|
|
/*
|
|
* Write a long word to memory
|
|
*/
|
|
static int
|
|
bdmDrvWriteLongWord (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
return (self->write_long_word) (self, ioc);
|
|
}
|
|
|
|
/*
|
|
* Write a word to memory
|
|
*/
|
|
static int
|
|
bdmDrvWriteWord (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
return (self->write_word) (self, ioc);
|
|
}
|
|
|
|
/*
|
|
* Write a byte to memory
|
|
*/
|
|
static int
|
|
bdmDrvWriteByte (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
return (self->write_byte) (self, ioc);
|
|
}
|
|
|
|
#ifdef BDM_BIT_BASH_PORT
|
|
|
|
/*
|
|
* Bit Bash the BDM signals. This is provided to allow low level
|
|
* bit bashing support for getting new BDM or target hardware
|
|
* working.
|
|
*/
|
|
static int
|
|
bdmDrvBitBash (struct BDM *self, struct BDMioctl *ioc)
|
|
{
|
|
if (self->bit_bash)
|
|
return (self->bit_bash) (self, ioc->value >> 16, ioc->value & 0xffff);
|
|
return -1;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
************************************************************************
|
|
* Driver Functions which are common to the different OS's *
|
|
************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Requires the OS to define `os_claim_io_ports' and
|
|
* `os_release_io_ports'. If your OS does not support this,
|
|
* do nothing and return an error code of 0.
|
|
*/
|
|
|
|
static int
|
|
bdm_open (unsigned int minor)
|
|
{
|
|
struct BDM *self;
|
|
int status, err = 0;
|
|
|
|
union {
|
|
char c[4];
|
|
uint32_t l;
|
|
} un;
|
|
|
|
if (minor >= (sizeof bdm_device_info / sizeof bdm_device_info[0]))
|
|
return ENODEV;
|
|
|
|
/*
|
|
* Determine what byte-swapping we'll need to do
|
|
*/
|
|
if (sizeof un.l != sizeof un.c) {
|
|
PRINTF ("bdm_open -- host machine sizeof (uint32_t) != sizeof (char[4])");
|
|
return ENODEV;
|
|
}
|
|
if ((sizeof (uint32_t) != 4) ||
|
|
(sizeof (short) != 2) ||
|
|
(sizeof (char) != 1)) {
|
|
PRINTF ("bdm_open -- host machine sizeof not appropriate");
|
|
return ENODEV;
|
|
}
|
|
un.c[0] = 0x01;
|
|
un.c[1] = 0x02;
|
|
un.c[2] = 0x03;
|
|
un.c[3] = 0x04;
|
|
if (un.l == 0x01020304) {
|
|
mustSwap = 0;
|
|
}
|
|
else if (un.l == 0x04030201) {
|
|
mustSwap = 1;
|
|
}
|
|
else {
|
|
PRINTF ("bdm_open -- host machine has peculiar byte ordering");
|
|
return ENODEV;
|
|
}
|
|
|
|
self = &bdm_device_info[minor];
|
|
|
|
if (self->debugFlag > 0)
|
|
PRINTF ("bdm_open -- minor %d\n", minor);
|
|
|
|
if (!self->exists)
|
|
return ENODEV;
|
|
if (self->isOpen)
|
|
return EBUSY;
|
|
|
|
/*
|
|
* Ask the OS to try and claim the port.
|
|
*/
|
|
|
|
err = os_claim_io_ports (self->name, self->portBase, 4);
|
|
|
|
if (err)
|
|
return err;
|
|
|
|
self->portsAreMine = 1;
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("bdm_open -- %s using port 0x%x.\n", self->name, self->portBase);
|
|
|
|
/*
|
|
* Set up the driver.
|
|
*/
|
|
|
|
status = bdmDrvInitHardware (self);
|
|
|
|
if (status & BDM_TARGETNC)
|
|
err = BDM_FAULT_CABLE;
|
|
else if (status & BDM_TARGETPOWER)
|
|
err = BDM_FAULT_POWER;
|
|
|
|
if (err) {
|
|
os_release_io_ports (self->portBase, 4);
|
|
self->portsAreMine = 0;
|
|
}
|
|
else {
|
|
os_lock_module ();
|
|
self->isOpen = 1;
|
|
}
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("BDMopen return %d, delayTimer %d\n", err, self->delayTimer);
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* The old Linux driver set the control port back to the value it
|
|
* had when the device was opened. This is good when the port is
|
|
* being shared between the BDM interface and a printer, but has
|
|
* the unfortunate side effect of freezing the target. This makes
|
|
* it inconvenient to use the debugger, or a downloader program,
|
|
* since the target freezes as soon as the debugger, or downloader,
|
|
* exits.
|
|
*/
|
|
static int
|
|
bdm_close (unsigned int minor)
|
|
{
|
|
struct BDM *self = &bdm_device_info[minor];
|
|
|
|
if (self->isOpen) {
|
|
bdmDrvReleaseChip (self);
|
|
if (self->exists && self->portsAreMine)
|
|
os_release_io_ports (self->portBase, 4);
|
|
self->portsAreMine = 0;
|
|
self->isOpen = 0;
|
|
os_unlock_module ();
|
|
}
|
|
|
|
if (self->debugFlag)
|
|
PRINTF ("BDM released\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
bdm_ioctl (unsigned int minor, unsigned int cmd, unsigned long arg)
|
|
{
|
|
struct BDM *self = &bdm_device_info[minor];
|
|
struct BDMioctl ioc;
|
|
int iarg;
|
|
int err = 0;
|
|
|
|
/*
|
|
* Pick up the argument
|
|
*/
|
|
if (self->debugFlag > 3)
|
|
PRINTF ("BDMioctl cmd:0x%x\n", cmd);
|
|
|
|
switch (cmd) {
|
|
case BDM_READ_REG:
|
|
case BDM_READ_CTLREG:
|
|
case BDM_READ_DBREG:
|
|
case BDM_READ_SYSREG:
|
|
case BDM_READ_LONGWORD:
|
|
case BDM_READ_WORD:
|
|
case BDM_READ_BYTE:
|
|
case BDM_WRITE_REG:
|
|
case BDM_WRITE_CTLREG:
|
|
case BDM_WRITE_DBREG:
|
|
case BDM_WRITE_SYSREG:
|
|
case BDM_WRITE_LONGWORD:
|
|
case BDM_WRITE_WORD:
|
|
case BDM_WRITE_BYTE:
|
|
err = os_copy_in ((void*) &ioc, (void*) arg, sizeof ioc);
|
|
break;
|
|
|
|
case BDM_SPEED:
|
|
case BDM_DEBUG:
|
|
case BDM_SET_CF_PST:
|
|
err = os_copy_in ((void*) &iarg, (void*) arg, sizeof iarg);
|
|
if (self->debugFlag > 3)
|
|
PRINTF ("BDMioctl cmd->iarg:0x%x\n", iarg);
|
|
break;
|
|
}
|
|
|
|
if (err)
|
|
return err;
|
|
|
|
/*
|
|
* Handle the request
|
|
*/
|
|
switch (cmd) {
|
|
case BDM_INIT:
|
|
iarg = bdmDrvInitHardware (self);
|
|
if (iarg & BDM_TARGETNC)
|
|
err = BDM_FAULT_CABLE;
|
|
else if (iarg & BDM_TARGETPOWER)
|
|
err = BDM_FAULT_POWER;
|
|
break;
|
|
|
|
case BDM_RESET_CHIP:
|
|
err = bdmDrvResetChip (self);
|
|
break;
|
|
|
|
case BDM_RESTART_CHIP:
|
|
err = bdmDrvRestartChip (self);
|
|
break;
|
|
|
|
case BDM_STOP_CHIP:
|
|
err = bdmDrvStopChip (self);
|
|
break;
|
|
|
|
case BDM_STEP_CHIP:
|
|
err = bdmDrvStepChip (self);
|
|
break;
|
|
|
|
case BDM_GO:
|
|
err = bdmDrvGo (self);
|
|
break;
|
|
|
|
case BDM_GET_STATUS:
|
|
iarg = bdmDrvGetStatus (self);
|
|
break;
|
|
|
|
case BDM_SPEED:
|
|
self->delayTimer = iarg;
|
|
if (self->debugFlag)
|
|
PRINTF ("delayTimer now %d\n", self->delayTimer);
|
|
break;
|
|
|
|
case BDM_DEBUG:
|
|
self->debugFlag = iarg;
|
|
if (self->debugFlag)
|
|
PRINTF ("debugFlag now %d\n", self->debugFlag);
|
|
break;
|
|
|
|
case BDM_RELEASE_CHIP:
|
|
err = bdmDrvReleaseChip (self);
|
|
break;
|
|
|
|
case BDM_READ_CTLREG:
|
|
err = bdmDrvReadSystemRegister (self, &ioc, BDM_SYS_REG_MODE_CONTROL);
|
|
break;
|
|
|
|
case BDM_READ_DBREG:
|
|
err = bdmDrvReadSystemRegister (self, &ioc, BDM_SYS_REG_MODE_DEBUG);
|
|
break;
|
|
|
|
case BDM_READ_REG:
|
|
err = bdmDrvReadProcessorRegister (self, &ioc);
|
|
break;
|
|
|
|
case BDM_READ_SYSREG:
|
|
err = bdmDrvReadSystemRegister (self, &ioc, BDM_SYS_REG_MODE_MAPPED);
|
|
break;
|
|
|
|
case BDM_READ_LONGWORD:
|
|
err = bdmDrvReadLongWord (self, &ioc);
|
|
break;
|
|
|
|
case BDM_READ_WORD:
|
|
err = bdmDrvReadWord (self, &ioc);
|
|
break;
|
|
|
|
case BDM_READ_BYTE:
|
|
err = bdmDrvReadByte (self, &ioc);
|
|
break;
|
|
|
|
case BDM_WRITE_CTLREG:
|
|
err = bdmDrvWriteSystemRegister (self, &ioc, BDM_SYS_REG_MODE_CONTROL);
|
|
break;
|
|
|
|
case BDM_WRITE_DBREG:
|
|
err = bdmDrvWriteSystemRegister (self, &ioc, BDM_SYS_REG_MODE_DEBUG);
|
|
break;
|
|
|
|
case BDM_WRITE_SYSREG:
|
|
err = bdmDrvWriteSystemRegister (self, &ioc, BDM_SYS_REG_MODE_MAPPED);
|
|
break;
|
|
|
|
case BDM_WRITE_REG:
|
|
err = bdmDrvWriteProcessorRegister (self, &ioc);
|
|
break;
|
|
|
|
case BDM_WRITE_LONGWORD:
|
|
err = bdmDrvWriteLongWord (self, &ioc);
|
|
break;
|
|
|
|
case BDM_WRITE_WORD:
|
|
err = bdmDrvWriteWord (self, &ioc);
|
|
break;
|
|
|
|
case BDM_WRITE_BYTE:
|
|
err = bdmDrvWriteByte (self, &ioc);
|
|
break;
|
|
|
|
case BDM_GET_CPU_TYPE:
|
|
iarg = self->processor;
|
|
break;
|
|
|
|
case BDM_GET_IF_TYPE:
|
|
iarg = self->interface;
|
|
break;
|
|
|
|
case BDM_GET_DRV_VER:
|
|
iarg = BDM_DRV_VERSION;
|
|
break;
|
|
|
|
case BDM_GET_CF_PST:
|
|
iarg = self->cf_use_pst;
|
|
break;
|
|
|
|
case BDM_SET_CF_PST:
|
|
self->cf_use_pst = iarg;
|
|
break;
|
|
|
|
default:
|
|
err = EINVAL;
|
|
break;
|
|
}
|
|
|
|
if (err)
|
|
return err;
|
|
|
|
/*
|
|
* Return the result if no error was found.
|
|
*/
|
|
switch (cmd) {
|
|
case BDM_READ_REG:
|
|
case BDM_READ_CTLREG:
|
|
case BDM_READ_DBREG:
|
|
case BDM_READ_SYSREG:
|
|
case BDM_READ_LONGWORD:
|
|
case BDM_READ_WORD:
|
|
case BDM_READ_BYTE:
|
|
err = os_copy_out ((void*) arg, (void*) &ioc, sizeof ioc);
|
|
break;
|
|
|
|
case BDM_GET_STATUS:
|
|
case BDM_GET_CPU_TYPE:
|
|
case BDM_GET_IF_TYPE:
|
|
case BDM_GET_DRV_VER:
|
|
case BDM_GET_CF_PST:
|
|
err = os_copy_out ((void*) arg, (void*) &iarg, sizeof iarg);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int
|
|
bdm_read (unsigned int minor, char *buf, int count)
|
|
{
|
|
struct BDM *self = &bdm_device_info[minor];
|
|
int nleft, ncopy;
|
|
int err;
|
|
|
|
nleft = count;
|
|
while (nleft) {
|
|
if (nleft > sizeof self->ioBuffer)
|
|
ncopy = sizeof self->ioBuffer;
|
|
else
|
|
ncopy = nleft;
|
|
err = bdmDrvFillBuf (self, ncopy);
|
|
if (err)
|
|
return err;
|
|
err = os_move_out (buf, self->ioBuffer, ncopy);
|
|
if (err)
|
|
return err;
|
|
nleft -= ncopy;
|
|
#ifndef BUF_INCREMENTED_BY_MOVE_OUT
|
|
buf += ncopy;
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
bdm_write (unsigned int minor, char *buf, int count)
|
|
{
|
|
struct BDM *self = &bdm_device_info[minor];
|
|
int nleft, ncopy;
|
|
int err;
|
|
|
|
nleft = count;
|
|
while (nleft) {
|
|
if (nleft > sizeof self->ioBuffer)
|
|
ncopy = sizeof self->ioBuffer;
|
|
else
|
|
ncopy = nleft;
|
|
err = os_move_in (self->ioBuffer, (void*) buf, ncopy);
|
|
if (err)
|
|
return err;
|
|
err = bdmDrvSendBuf (self, ncopy);
|
|
if (err)
|
|
return err;
|
|
nleft -= ncopy;
|
|
#ifndef BUF_INCREMENTED_BY_MOVE_IN
|
|
buf += ncopy;
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|