1968 lines
54 KiB
C
1968 lines
54 KiB
C
/*
|
|
* $Id: bdm.c,v 1.8 2006/12/28 13:04:58 ppisa Exp $
|
|
*
|
|
* Linux Device Driver BDM Interface
|
|
* based on the PD driver package by Scott Howard, Feb 93
|
|
* PD version ported to Linux by M.Schraut, Feb 95
|
|
* enhancements from W. Eric Norum (eric@skatter.usask.ca), who did
|
|
* a Next-Step-Port in Jun 95
|
|
* tested for kernel version 1.3.57
|
|
* (C) 1995, 1996 Technische Universitaet Muenchen, L. f. Prozessrechner
|
|
* (C) 1997 Gunter Magin, Muenchen
|
|
*
|
|
* Modified by Pavel Pisa pisa@cmp.felk.cvut.cz 1997 - 2003
|
|
* tested for kernel version 2.2.x and 2.4.x with ICD and PD cables
|
|
* new k_compat.h for kernels up to 2.4.0
|
|
*
|
|
* 2003/04/27 modified by Juergen Eder <Juergen.Eder@gmx.de>:
|
|
* Compatible with parport driver
|
|
* define in makefile: -DWITH_PARPORT_SUPPORT
|
|
*
|
|
|
|
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, 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; see the file COPYING. If not, write to
|
|
the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#undef REALLY_SLOW_IO
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/version.h>
|
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17)
|
|
#include <linux/config.h>
|
|
#endif
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,60)
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
|
|
#include <linux/devfs_fs_kernel.h>
|
|
#endif
|
|
#else /* 2.5.60 */
|
|
#ifdef MODVERSIONS
|
|
#include <linux/modversions.h>
|
|
#endif /* MODVERSIONS */
|
|
#endif /* 2.5.60 */
|
|
#include <linux/errno.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/ioport.h>
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) // fixme ?
|
|
#include <linux/slab.h> /* instead of malloc.h */
|
|
#else
|
|
#include <linux/malloc.h>
|
|
#endif
|
|
#include <linux/sys.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/delay.h>
|
|
#ifdef WITH_PARPORT_SUPPORT
|
|
#include <linux/parport.h>
|
|
#endif
|
|
#include <asm/segment.h>
|
|
#include <asm/system.h>
|
|
#include <asm/io.h>
|
|
#include "bdm.h"
|
|
#include "k_compat.h"
|
|
|
|
#if (LINUX_VERSION_CODE >= VERSION(2,4,0))
|
|
#define BDM_WITH_DEVFS
|
|
#include <linux/miscdevice.h>
|
|
kc_devfs_handle_t bdm_devfs_handle=NULL;
|
|
#endif
|
|
|
|
#define BDM_DEVFS_DIR_NAME "m683xx-bdm"
|
|
|
|
MODULE_SUPPORTED_DEVICE("m683xx-bdm");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("Motorola m683xx BDM debugging interface");
|
|
|
|
#define BDM_DRIVER_VERSION 4
|
|
|
|
#if !defined PD_INTERFACE && !defined ICD_INTERFACE
|
|
#error You have to decide for the PD interface or the ICD interface
|
|
#error Check the Makefile and uncomment the right line
|
|
#endif
|
|
|
|
#if !defined ICD_INTERFACE && defined EFIICDISP
|
|
#error It makes no sense to enable ISP programming support in a driver not
|
|
#error for ICD compatible devices
|
|
#error Check the Makefile and either disable EFIICDISP or enable ICD_INTERFACE
|
|
#endif
|
|
|
|
#define BYTECOUNT_FOR_BEING_NICE 64
|
|
/* no of bytes to transfer before giving
|
|
* other tasks opportunity being scheduled */
|
|
#define BDM_WAITCNT 0xffff /* no of loops to wait for response */
|
|
#define BITS 15 /* shift 16bit into 32 bit by 15 */
|
|
/* -.1.Bit always 0 (Statusbit) */
|
|
|
|
/* declaration of local variables */
|
|
#define BDM_DLY_DEFAULT 30
|
|
|
|
#define BDM_LONG_DLY(d) (2*d/3 == 0) ? 1 : (2*d/3)
|
|
#define BDM_HALF_DLY(d) (d/2 == 0) ? 1 : (d/2)
|
|
#define BDM_SHORT_DLY(d) (d/3 == 0) ? 1 : (d/3)
|
|
#define BDM_MIN_DLY(d) (d/30 == 0) ? 1 : (d/30)
|
|
static int bdm_norm_dly = BDM_DLY_DEFAULT;
|
|
static int bdm_long_dly = BDM_LONG_DLY(BDM_DLY_DEFAULT);
|
|
static int bdm_half_dly = BDM_HALF_DLY(BDM_DLY_DEFAULT);
|
|
static int bdm_short_dly = BDM_SHORT_DLY(BDM_DLY_DEFAULT);
|
|
static int bdm_min_dly = BDM_MIN_DLY(BDM_DLY_DEFAULT);
|
|
static int bdm_reset_dly = 0;
|
|
static int bdm_no_ser_dly_mode = 0; /* mode for maximal speed */
|
|
#define SER_CLK_DSO_WAIT 0x100 /* in fast mode, delay only before */
|
|
/* explicit serial transfers */
|
|
|
|
static unsigned int bdm_debug_level = BDM_DEBUG_NONE;
|
|
static int bdm_version = BDM_DRIVER_VERSION;
|
|
static int bdm_sense = 1; /* do sense power & connected */
|
|
|
|
typedef unsigned int status_bitset;
|
|
|
|
#define BDM_DESCR_MAGIC 0x42444daa
|
|
|
|
typedef struct _bdm_descr_t bdm_descr_t;
|
|
struct _bdm_descr_t {
|
|
unsigned int magic;
|
|
#ifndef WITH_PARPORT_SUPPORT
|
|
unsigned int port_adr;
|
|
#else /* WITH_PARPORT_SUPPORT */
|
|
unsigned int parport_nr;
|
|
#endif /* WITH_PARPORT_SUPPORT */
|
|
unsigned int minor;
|
|
status_bitset (*init) (bdm_descr_t *);
|
|
int (*deinit) (bdm_descr_t *);
|
|
status_bitset (*getstatus) (bdm_descr_t *);
|
|
int (*restart_chip) (bdm_descr_t *);
|
|
int (*release_chip) (bdm_descr_t *);
|
|
int (*stop_chip) (bdm_descr_t *);
|
|
int (*step_chip) (bdm_descr_t *);
|
|
int (*reset_chip) (bdm_descr_t *);
|
|
int (*ser_clk) (bdm_descr_t *, short, int);
|
|
int (*set_led) (bdm_descr_t *, int);
|
|
status_bitset (*resynchro) (bdm_descr_t *);
|
|
char *name;
|
|
unsigned int old_ctl; /* save old control port settings */
|
|
unsigned int shadow_ctl; /* shadow reg. of control port for read */
|
|
};
|
|
|
|
/* generic helper functions */
|
|
|
|
#ifndef WITH_PARPORT_SUPPORT
|
|
|
|
#define PORT_ADDRESSE_LP1 0x378 /* LPT1 */
|
|
#define PORT_ADDRESSE_LP2 0x278 /* LPT2 */
|
|
#define PORT_ADDRESSE_LP3 0x3bc /* LPT3 */
|
|
|
|
#define BDM_DATA(d) (d->port_adr)
|
|
#define BDM_STAT(d) (d->port_adr + 1)
|
|
#define BDM_CTRL(d) (d->port_adr + 2)
|
|
|
|
static unsigned char
|
|
bdm_in_ctl(bdm_descr_t * descr)
|
|
{
|
|
return inb(BDM_CTRL(descr));
|
|
}
|
|
|
|
static void
|
|
bdm_out_ctl(int data, bdm_descr_t * descr)
|
|
{
|
|
outb(data,BDM_CTRL(descr));
|
|
descr->shadow_ctl=data;
|
|
}
|
|
|
|
static unsigned char
|
|
bdm_in_st(bdm_descr_t * descr)
|
|
{
|
|
return inb(BDM_STAT(descr));
|
|
}
|
|
|
|
static void
|
|
bdm_out_data(int data, bdm_descr_t * descr)
|
|
{
|
|
outb(data,BDM_DATA(descr));
|
|
}
|
|
|
|
static unsigned char
|
|
bdm_in_data(bdm_descr_t * descr)
|
|
{
|
|
return inb(BDM_DATA(descr));
|
|
}
|
|
|
|
#else /* WITH_PARPORT_SUPPORT */
|
|
|
|
#define PORT_ADDRESSE_LP1 0
|
|
#define PORT_ADDRESSE_LP2 1
|
|
#define PORT_ADDRESSE_LP3 2
|
|
|
|
#define MAX_BDM_PORTS 3
|
|
static struct pardevice *bdm_parports[MAX_BDM_PORTS];
|
|
|
|
static struct pardevice *
|
|
bdm_get_parport(bdm_descr_t * descr)
|
|
{
|
|
if((unsigned)descr->parport_nr>=MAX_BDM_PORTS)
|
|
return NULL;
|
|
return bdm_parports[descr->parport_nr];
|
|
}
|
|
|
|
/*static int
|
|
bdm_get_parport_num(bdm_descr_t * descr)
|
|
{
|
|
return descr->parport_nr;
|
|
}*/
|
|
|
|
static void
|
|
bdm_out_ctl(int data, bdm_descr_t * descr)
|
|
{
|
|
struct pardevice *p;
|
|
p = bdm_get_parport(descr);
|
|
if(!p)
|
|
return;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
|
parport_write_control(p->port,data & ~0x20);
|
|
if(data & 0x20)
|
|
parport_data_reverse(p->port);
|
|
else
|
|
parport_data_forward(p->port);
|
|
#else
|
|
parport_write_control(p->port,data);
|
|
#endif
|
|
descr->shadow_ctl=data;
|
|
}
|
|
|
|
static unsigned char
|
|
bdm_in_ctl(bdm_descr_t * descr)
|
|
{
|
|
struct pardevice *p;
|
|
p = bdm_get_parport(descr);
|
|
if(!p)
|
|
return 0;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
|
/* There is no 'parport_read_control()' function -> use my own variable */
|
|
return descr->shadow_ctl;
|
|
#else
|
|
return parport_read_control(p->port);
|
|
#endif
|
|
}
|
|
|
|
static unsigned char
|
|
bdm_in_st(bdm_descr_t * descr)
|
|
{
|
|
struct pardevice *p;
|
|
p = bdm_get_parport(descr);
|
|
if(!p)
|
|
return 0;
|
|
return parport_read_status(p->port);
|
|
}
|
|
|
|
static void
|
|
bdm_out_data(int data, bdm_descr_t * descr)
|
|
{
|
|
struct pardevice *p;
|
|
p = bdm_get_parport(descr);
|
|
if(!p)
|
|
return;
|
|
parport_write_data(p->port,data);
|
|
}
|
|
|
|
static unsigned char
|
|
bdm_in_data(bdm_descr_t * descr)
|
|
{
|
|
struct pardevice *p;
|
|
p = bdm_get_parport(descr);
|
|
if(!p)
|
|
return 0;
|
|
return parport_read_data(p->port);
|
|
}
|
|
|
|
#endif /* WITH_PARPORT_SUPPORT */
|
|
|
|
/* slow down host for not overrunning target */
|
|
static void
|
|
bdm_delay(int counter)
|
|
{
|
|
|
|
if (counter < (1000000/HZ)) {
|
|
while (counter > 1000) {
|
|
udelay(1000); counter -= 1000;
|
|
}
|
|
udelay(counter);
|
|
} else {
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
schedule_timeout(counter/(1000000/HZ));
|
|
}
|
|
#if NEVER
|
|
while (counter--) {
|
|
asm volatile ("nop");
|
|
}
|
|
#endif /* NEVER */
|
|
}
|
|
|
|
|
|
static void
|
|
bdm_error(int bdm_type)
|
|
{
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
switch (bdm_type) {
|
|
case -BDM_FAULT_UNKNOWN:
|
|
printk("Unknown Error - check speed\n");
|
|
break;
|
|
case -BDM_FAULT_POWER:
|
|
printk("Power failed on Target MCU\n");
|
|
break;
|
|
case -BDM_FAULT_CABLE:
|
|
printk("Cable disconnected on Target MCU\n");
|
|
break;
|
|
case -BDM_FAULT_RESPONSE:
|
|
printk("No response from Target MCU\n");
|
|
break;
|
|
case -BDM_FAULT_RESET:
|
|
printk("Can t clock Target MCU while on Reset\n");
|
|
break;
|
|
case -BDM_FAULT_PORT:
|
|
printk("Wrong Port\n");
|
|
break;
|
|
case -BDM_FAULT_BERR:
|
|
printk("Buserror\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define do_case(x) case x: ret = #x; break;
|
|
|
|
static char *
|
|
bdm_get_ioctl_name(int ioctl)
|
|
{
|
|
char *ret;
|
|
switch (ioctl) {
|
|
do_case(BDM_INIT);
|
|
do_case(BDM_DEINIT);
|
|
do_case(BDM_RESET_CHIP);
|
|
do_case(BDM_RESTART_CHIP);
|
|
do_case(BDM_STOP_CHIP);
|
|
do_case(BDM_STEP_CHIP);
|
|
do_case(BDM_GET_STATUS);
|
|
do_case(BDM_SPEED);
|
|
do_case(BDM_RELEASE_CHIP);
|
|
do_case(BDM_DEBUG_LEVEL);
|
|
do_case(BDM_GET_VERSION);
|
|
do_case(BDM_SENSECABLE);
|
|
do_case(BDM_RESPW);
|
|
#ifdef EFIICDISP
|
|
do_case(BDM_ISPSET);
|
|
do_case(BDM_ISPGET);
|
|
#endif
|
|
default:
|
|
ret = "Unknown ioctl";
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
#ifdef PD_INTERFACE
|
|
|
|
/*
|
|
* Parallel port bit assignments for the PD interface (minor-numbers 0-2)
|
|
*
|
|
* Status register (bits 0-2 not used):
|
|
* +---+---+---+---+---+---+---+---+
|
|
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
|
* +---+---+---+---+---+---+---+---+
|
|
* | | | | |
|
|
* | | | | +--- Target FREEZE line
|
|
* | | | | 1 - Target is in background mode
|
|
* | | | | 0 - Target is not background mode
|
|
* | | | |
|
|
* | | | +------- Not used
|
|
* | | |
|
|
* | | +----------- Serial data from target
|
|
* | | 1 - `0' from target
|
|
* | | 0 - `1' from target
|
|
* | |
|
|
* | +--------------- Target power
|
|
* | 1 - Target power is ON
|
|
* | 0 - Target power is OFF
|
|
* |
|
|
* +------------------- Target connected
|
|
* 1 - Target is connected
|
|
* 0 - Target is not connected
|
|
*
|
|
* Control register (bits 4-7 not used):
|
|
* +---+---+---+---+
|
|
* | 3 | 2 | 1 | 0 |
|
|
* +---+---+---+---+
|
|
* | | | |
|
|
* | | | +--- Target BKPT* /DSCLK line
|
|
* | | | Write 1 - Drive BKPT* /DSCLK line LOW
|
|
* | | | Write 0 - Drive BKPT* /DSCLK line HIGH
|
|
* | | |
|
|
* | | +------- Target RESET* line
|
|
* | | Write 1 - Force RESET* LOW
|
|
* | | Write 0 - Allow monitoring of RESET*
|
|
* | | Read 1 - RESET* is LOW
|
|
* | | Read 0 - RESET* is HIGH
|
|
* | |
|
|
* | +----------- Serial data to target
|
|
* | Write 0 - Send `0' to target
|
|
* | Write 1 - Send `1' to target
|
|
* |
|
|
* +--------------- Control single-step flip-flop
|
|
* Write 1 - Clear flip-flop
|
|
* BKPT* /DSCLK is controlled by bit 0.
|
|
* Write 0 - Allow flip-flop operation
|
|
* Falling edge of IFETCH* /DSI clocks a `1'
|
|
* into the flip-flop and drive BKPT* /DSCLK
|
|
* LOW, causing a breakpoint.
|
|
*/
|
|
|
|
#define BDMPD_DSCLK 1 /* data shift clock / breakpoint pin */
|
|
#define BDMPD_RST_OUT 2 /* set high to force reset on MCU */
|
|
#define BDMPD_DSI 4 /* data shift input Host->MCU */
|
|
#define BDMPD_STEP_OUT 8 /* set low to gate IFETCH onto BKPT */
|
|
|
|
#define BDMPD_FREEZE 8 /* FREEZE asserted when MCU stopped */
|
|
#define BDMPD_DSO 0x20 /* data shift output MCU-.Host */
|
|
#define BDMPD_PWR_DWN 0x40 /* power down - low when Vcc failed */
|
|
#define BDMPD_NC 0x80 /* not connected - low when unplugged */
|
|
|
|
|
|
static status_bitset
|
|
bdm_pd_init(bdm_descr_t *descr)
|
|
{
|
|
status_bitset status;
|
|
bdm_out_ctl(BDMPD_STEP_OUT | BDMPD_DSCLK, descr);
|
|
/* force breakpoint */
|
|
bdm_delay(bdm_min_dly);
|
|
status = descr->getstatus(descr); /* eg connected, power etc. */
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_init minor %d status %d\n",
|
|
descr->minor, status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static int
|
|
bdm_pd_deinit(bdm_descr_t * descr)
|
|
{
|
|
#if LP_PORT_RESTORE
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_deinit: restoring %#x\n", descr->old_ctl);
|
|
}
|
|
bdm_out_ctl(descr->old_ctl, descr);
|
|
/* restore old control port settings */
|
|
#endif /* LP_PORT_RESTORE */
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
/* read status byte from statusport and translate into bitset */
|
|
static status_bitset
|
|
bdm_pd_getstatus(bdm_descr_t *descr)
|
|
{
|
|
unsigned char temp = bdm_in_st(descr);
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("bdm_pd_getstatus minor=%d res=%#x\n", descr->minor, temp);
|
|
}
|
|
if (bdm_sense) {
|
|
if (!(temp & BDMPD_NC))
|
|
return BDM_TARGETNC;
|
|
if (!(temp & BDMPD_PWR_DWN))
|
|
return BDM_TARGETPOWER;
|
|
}
|
|
return (temp & BDMPD_FREEZE ? BDM_TARGETSTOPPED : 0) |
|
|
(bdm_in_ctl(descr) & BDMPD_RST_OUT ? BDM_TARGETRESET : 0);
|
|
}
|
|
|
|
/* this routine is last resort one, it is able resyncronize with MCU,
|
|
when some spike on DSCLK has disturbed MCU */
|
|
static status_bitset
|
|
bdm_pd_resynchro(bdm_descr_t *descr)
|
|
{
|
|
int i;
|
|
descr->ser_clk(descr, BDM_NOP_CMD, 0); /* send NOP command */
|
|
descr->ser_clk(descr, BDM_NOP_CMD, 0); /* send NOP command */
|
|
descr->ser_clk(descr, BDM_NOP_CMD, 0); /* send NOP command */
|
|
i=17; /* maximal number disturb in bit shift */
|
|
while(i--)
|
|
{
|
|
if((bdm_in_st(descr) & BDMPD_DSO))
|
|
return BDM_FAULT_NOERROR; /* DSO becomes 0 => OK */
|
|
bdm_out_ctl( BDMPD_STEP_OUT | BDMPD_DSCLK, descr); /* DSCLK=0 */
|
|
bdm_delay(bdm_norm_dly);
|
|
bdm_out_ctl( BDMPD_STEP_OUT , descr); /* DSCLK=1 */
|
|
bdm_delay(bdm_norm_dly);
|
|
}
|
|
return -BDM_FAULT_UNKNOWN;
|
|
}
|
|
|
|
/* restart chip and stop on first execution fetch */
|
|
static int
|
|
bdm_pd_restart_chip(bdm_descr_t * descr)
|
|
{
|
|
unsigned bdm_Loop_Count = 0;
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_restart_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
bdm_out_ctl(BDMPD_DSCLK, descr);
|
|
bdm_out_ctl(BDMPD_RST_OUT | BDMPD_DSCLK, descr);
|
|
bdm_delay(bdm_norm_dly+bdm_reset_dly);
|
|
bdm_out_ctl(BDMPD_DSCLK, descr);
|
|
bdm_delay(bdm_norm_dly);
|
|
bdm_out_ctl(BDMPD_STEP_OUT | BDMPD_DSCLK, descr);
|
|
for (bdm_Loop_Count = 0xffff; bdm_Loop_Count; bdm_Loop_Count--)
|
|
if (bdm_in_st(descr) & BDMPD_FREEZE)
|
|
break;
|
|
if (!bdm_Loop_Count) {
|
|
bdm_error(-BDM_FAULT_RESPONSE);
|
|
return -BDM_FAULT_RESPONSE;
|
|
} else {
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* stop running target */
|
|
static int
|
|
bdm_pd_stop_chip(bdm_descr_t * descr)
|
|
{
|
|
unsigned int bdm_ctr;
|
|
int return_value;
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_stop_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
if (bdm_in_st(descr) & BDMPD_FREEZE) {
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_stop_chip: already frozen..\n");
|
|
};
|
|
/* ensures no spike on BKPT/DSCLK in bdm_ser_clk */
|
|
bdm_out_ctl(BDMPD_DSCLK, descr);
|
|
bdm_delay(bdm_short_dly);
|
|
bdm_out_ctl(BDMPD_DSCLK | BDMPD_STEP_OUT, descr);
|
|
return BDM_FAULT_NOERROR; /* target was already halted */
|
|
}
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_stop_chip: was not frozen..\n");
|
|
}
|
|
return_value = -BDM_FAULT_UNKNOWN;
|
|
|
|
/* bdm_out_ctl(BDMPD_DSCLK | BDMPD_STEP_OUT, descr); */
|
|
bdm_out_ctl(BDMPD_DSCLK*0, descr);
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_stop_chip: armed stop\n");
|
|
}
|
|
for (bdm_ctr = BDM_WAITCNT; bdm_ctr; bdm_ctr--) {
|
|
if ((bdm_in_st(descr)) & BDMPD_FREEZE) {
|
|
return_value = BDM_FAULT_NOERROR; /* target is now halted */
|
|
break;
|
|
}
|
|
bdm_delay(bdm_min_dly);
|
|
}
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_stop_chip: after wait-for-freeze: cntr = %d\n",
|
|
BDM_WAITCNT-bdm_ctr);
|
|
}
|
|
bdm_out_ctl(BDMPD_DSCLK, descr);
|
|
bdm_delay(bdm_norm_dly);
|
|
bdm_out_ctl(BDMPD_DSCLK | BDMPD_STEP_OUT, descr);
|
|
|
|
if (!bdm_ctr) {
|
|
bdm_error(-BDM_FAULT_RESPONSE);
|
|
return -BDM_FAULT_RESPONSE;
|
|
}
|
|
#ifdef BDM_TRY_RESYNCHRO
|
|
descr->resynchro(descr); /* tries to find correct 17 bit boundary */
|
|
#endif /* BDM_TRY_RESYNCHRO */
|
|
return return_value;
|
|
}
|
|
|
|
|
|
|
|
/* single stepping target mcu */
|
|
static int
|
|
bdm_pd_step_chip(bdm_descr_t * descr)
|
|
{
|
|
int tester;
|
|
unsigned short DataOut = (BDM_GO_CMD & 1 ? BDMPD_DSI : 0);
|
|
|
|
status_bitset bdm_stat = descr->getstatus(descr);
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_step_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
if (bdm_stat & BDM_TARGETRESET) {
|
|
bdm_error(-BDM_FAULT_RESET);
|
|
return -BDM_FAULT_RESET;
|
|
}
|
|
if (bdm_stat & BDM_TARGETNC) {
|
|
bdm_error(-BDM_FAULT_CABLE);
|
|
return -BDM_FAULT_CABLE;
|
|
}
|
|
if (bdm_stat & BDM_TARGETPOWER) {
|
|
bdm_error(-BDM_FAULT_POWER);
|
|
return -BDM_FAULT_POWER;
|
|
}
|
|
tester = descr->ser_clk(descr, BDM_GO_CMD, 1);
|
|
switch (tester) {
|
|
case -BDM_FAULT_RESET:
|
|
case -BDM_FAULT_CABLE:
|
|
case -BDM_FAULT_POWER:
|
|
return tester;
|
|
}
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("stepchip sent: %x got : %x\n",
|
|
BDM_GO_CMD, (unsigned int) tester);
|
|
printk("last answerbit : %x\n", !(bdm_in_st(descr) & BDMPD_DSO));
|
|
}
|
|
/*
|
|
* this is the place the inb() should take place, but on step_chip, we
|
|
* don't care for the reply of CPU32, coming in when sending the cmd
|
|
*/
|
|
bdm_out_ctl(BDMPD_DSCLK | BDMPD_STEP_OUT | DataOut, descr);
|
|
bdm_delay(bdm_norm_dly);
|
|
bdm_out_ctl(BDMPD_DSCLK | DataOut, descr);
|
|
bdm_delay(bdm_long_dly);
|
|
/* leave more time to avoid a glitch on DSCLK*/
|
|
bdm_out_ctl(DataOut, descr);
|
|
/* FREEZE goes low after */
|
|
/* 10 CPU32 clock cycles, it is about 700ns @ 16 MHz */
|
|
bdm_delay(bdm_long_dly);
|
|
#ifdef BDM_TRY_RESYNCHRO
|
|
descr->stop_chip(descr);
|
|
return descr->resynchro(descr);
|
|
#else /* BDM_TRY_RESYNCHRO */
|
|
return descr->stop_chip(descr);
|
|
#endif /* BDM_TRY_RESYNCHRO */
|
|
}
|
|
|
|
/* reset target chip without asserting bkpt/!dsclk */
|
|
static int
|
|
bdm_pd_release_chip(bdm_descr_t * descr)
|
|
{
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_release_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
bdm_out_ctl(BDMPD_DSCLK | BDMPD_STEP_OUT, descr);
|
|
bdm_delay(bdm_short_dly);
|
|
bdm_out_ctl(BDMPD_DSCLK | BDMPD_RST_OUT | BDMPD_STEP_OUT, descr);
|
|
bdm_delay(bdm_norm_dly);
|
|
bdm_out_ctl(BDMPD_STEP_OUT, descr);
|
|
bdm_delay(bdm_short_dly);
|
|
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
/*
|
|
* Restart chip, enable background debugging mode, halt on first fetch
|
|
*
|
|
* The software from the Motorola BBS tries to have the target
|
|
* chip begin execution, but that doesn't work very reliably.
|
|
* The RESETH* line rises rather slowly, so sometimes the BKPT* / DSCLK
|
|
* would be seen low, and sometimes it wouldn't.
|
|
*/
|
|
static int
|
|
bdm_pd_reset_chip(bdm_descr_t * descr)
|
|
{
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_pd_reset_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
#if NEVER
|
|
/* this is the original Howard code */
|
|
bdm_out_ctl(BDMPD_RST_OUT | BDMPD_STEP_OUT, descr);
|
|
bdm_delay(bdm_norm_dly);
|
|
bdm_out_ctl(BDMPD_STEP_OUT, descr);
|
|
#endif /* NEVER */
|
|
|
|
|
|
/* this is suggested by Eric Norum */
|
|
bdm_out_ctl(BDMPD_DSCLK | BDMPD_RST_OUT, descr);
|
|
bdm_delay(bdm_norm_dly+bdm_reset_dly);
|
|
bdm_out_ctl(BDMPD_DSCLK, descr);
|
|
bdm_delay(bdm_norm_dly+bdm_reset_dly);
|
|
bdm_out_ctl(BDMPD_DSCLK | BDMPD_STEP_OUT, descr);
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
|
|
/* serial software protokoll for bdm-pd-interface */
|
|
static int
|
|
bdm_pd_ser_clk(bdm_descr_t * descr, short bdm_value, int delay_bits)
|
|
{
|
|
unsigned int ShiftRegister;
|
|
unsigned char DataOut;
|
|
unsigned counter;
|
|
unsigned bdm_stat = descr->getstatus(descr);
|
|
|
|
ShiftRegister = bdm_value;
|
|
ShiftRegister <<= BITS;
|
|
if (bdm_stat & BDM_TARGETRESET) { /*error checking */
|
|
bdm_error(-BDM_FAULT_RESET);
|
|
return -BDM_FAULT_RESET;
|
|
}
|
|
if (bdm_stat & BDM_TARGETNC) {
|
|
bdm_error(-BDM_FAULT_CABLE);
|
|
return -BDM_FAULT_CABLE;
|
|
}
|
|
if (bdm_stat & BDM_TARGETPOWER) {
|
|
bdm_error(-BDM_FAULT_POWER);
|
|
return -BDM_FAULT_POWER;
|
|
}
|
|
if(!(bdm_stat & BDM_TARGETSTOPPED))
|
|
{ if (bdm_debug_level >= BDM_DEBUG_SOME)
|
|
printk("bdm_ser_clk stop target first minor=%d\n", descr->minor);
|
|
if(descr->stop_chip(descr)!=BDM_FAULT_NOERROR)
|
|
{ printk("bdm_ser_clk can't stop it minor=%d\n", descr->minor);
|
|
return -BDM_FAULT_RESPONSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We can get there with DSCLK high or low
|
|
* but next code is OK for both cases
|
|
* first ensures DSCLK low => it frozes transmit shift
|
|
* register against CPU32 updates until 17 bits are sent
|
|
* and then clocks transmit shift register by DSCLK high
|
|
*/
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("bdm_pd_ser_clk: writing %5x\n", bdm_value);
|
|
}
|
|
if(bdm_no_ser_dly_mode && (delay_bits&SER_CLK_DSO_WAIT))
|
|
{ /* Wait for DSO to become 0 to indicate ready
|
|
* according CPU32UM, DSO is updated as long as
|
|
* DSCLK is high
|
|
*/
|
|
int wait_cnt;
|
|
for(wait_cnt=0;wait_cnt<100;wait_cnt++)
|
|
{ if (bdm_in_st(descr) & BDMPD_DSO)
|
|
break; /* DSO becomed zerro already */
|
|
bdm_delay(bdm_min_dly);
|
|
}
|
|
if(wait_cnt && (bdm_debug_level >= BDM_DEBUG_SOME))
|
|
printk("bdm_pd_ser_clk: ready after %d cycles\n",
|
|
wait_cnt);
|
|
}
|
|
|
|
counter = 32 - BITS - (delay_bits&0xff);
|
|
while (counter--) {
|
|
DataOut = ((ShiftRegister & 0x80000000) ? BDMPD_DSI : 0);
|
|
/*if 1 then dsi=1*/
|
|
ShiftRegister <<= 1; /*shift one bit left*/
|
|
bdm_out_ctl(DataOut | BDMPD_STEP_OUT | BDMPD_DSCLK, descr);
|
|
if(!bdm_no_ser_dly_mode)
|
|
bdm_delay(bdm_half_dly);
|
|
if (!(bdm_in_st(descr) & BDMPD_DSO))
|
|
ShiftRegister |= 1; /*put 1 on 0.bit */
|
|
bdm_out_ctl(DataOut | BDMPD_STEP_OUT, descr);
|
|
if(!bdm_no_ser_dly_mode)
|
|
bdm_delay(bdm_norm_dly);
|
|
}
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("bdm_pd_ser_clk: read %5x bits %d\n",
|
|
ShiftRegister, delay_bits);
|
|
}
|
|
#ifdef FIXME
|
|
if (!(delay_bits&0xff) && (ShiftRegister & 0x10000)) switch (ShiftRegister) {
|
|
case 0x1ffff: /* no valid command return */
|
|
return -BDM_FAULT_NVC;
|
|
case 0x10001:
|
|
return -BDM_FAULT_BERR;
|
|
case 0x10000:
|
|
return BDM_NOTE_NOTREADY;
|
|
default: ;
|
|
}
|
|
#endif /* FIXME */
|
|
return ShiftRegister;
|
|
}
|
|
|
|
/* switch LED if available */
|
|
static int
|
|
bdm_pd_setled(bdm_descr_t * descr, int switchstate)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef ICD_INTERFACE
|
|
/*
|
|
* Parallel port bit assignments for the ICD interface (minor-numbers 4-6)
|
|
*
|
|
* Status register
|
|
* +---+---+---+---+---+---+---+---+
|
|
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
|
* +---+---+---+---+---+---+---+---+
|
|
* | | | | |
|
|
* | | | | +--- ICD detection
|
|
* | | | | must follow LED level
|
|
* | | | |
|
|
* | | | +------- Power Detection
|
|
* | | | 1 - Power available
|
|
* | | | 0 - no Power
|
|
* | | |
|
|
* | | +----------- Jumper State
|
|
* | | 1 - Jumper closed
|
|
* | | 0 - Jumper open
|
|
* | |
|
|
* | +--------------- Target FREEZE line
|
|
* | 1 - Target is in background mode
|
|
* | 0 - Target is not background mode
|
|
* |
|
|
* +------------------- Serial data from target
|
|
* 1 - `0' from target
|
|
* 0 - `1' from target
|
|
*
|
|
* Data register
|
|
* +---+---+---+---+---+---+---+---+
|
|
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
|
* +---+---+---+---+---+---+---+---+
|
|
* | | | | | | | |
|
|
* | | | | | | | +--- Serial data to target
|
|
* | | | | | | | Write 1: Send 1 to target
|
|
* | | | | | | | Write 0: Send 0 to target
|
|
* | | | | | | | Signal gets to target, if OE is 1
|
|
* | | | | | | | and target is in FREEZE mode
|
|
* | | | | | | |
|
|
* | | | | | | +------- Clock
|
|
* | | | | | | if target in freeze mode, then:
|
|
* | | | | | | Write 1: drive BKPT* /DSCLK 1
|
|
* | | | | | | Write 0: drive BKPT* /DSCLK 0
|
|
* | | | | | |
|
|
* | | | | | +----------- BREAK
|
|
* | | | | | if target not in freeze mode, then:
|
|
* | | | | | Write 0: drive BKPT* /DSCLK 0
|
|
* | | | | | line determines single stepping
|
|
* | | | | | on leaving BGND mode:
|
|
* | | | | | Write 0: do single step
|
|
* | | | | | Write 1: continue normally
|
|
* | | | | |
|
|
* | | | | +--------------- RESET
|
|
* | | | | Write 0: pull reset low
|
|
* | | | | Write 1: release reset line
|
|
* | | | |
|
|
* | | | +--- OE
|
|
* | | | Write 0 - DSI is tristated
|
|
* | | | Write 1 - DSI pin is forced to level of serial data
|
|
* | | |
|
|
* | | +------- LED (not implemented everywhere..)
|
|
* | | Write 1 - turn on LED
|
|
* | | Write 0 - turn off LED
|
|
* | |
|
|
* | +----------- ERROR
|
|
* | Write 0 - BERR output is tristated
|
|
* | Write 1 - BERR is pulled low
|
|
* |
|
|
* +--------------- spare
|
|
*/
|
|
|
|
/* data register bit definitions */
|
|
#define BDMICD_DSI 0x01 /* data shift input Host->MCU */
|
|
#define BDMICD_DSCLK 0x02 /* data shift clock / breakpoint pin */
|
|
#define BDMICD_STEP_OUT 0x04 /* set low to force breakpoint */
|
|
#define BDMICD_RST_OUT 0x08 /* set low to force reset on MCU */
|
|
#define BDMICD_OE 0x10 /* set to a 1 to enable DSI */
|
|
#define BDMICD_LED 0x20 /* set to 1 to turn on LED */
|
|
#define BDMICD_FORCE_BERR 0x40 /* set to a 1 to force BERR on target */
|
|
|
|
/* status register bit definitions */
|
|
#define BDMICD_DSO 0x80 /* serial data from target */
|
|
#define BDMICD_FREEZE 0x40 /* 1 if target is frozen */
|
|
#define BDMICD_JMPR 0x20 /* 1 if jumper is set */
|
|
#define BDMICD_PWR 0x10 /* 1 if power available */
|
|
#define BDMICD_ICDDETECT 0x08 /* must follow LED */
|
|
|
|
/* control register bit definitions */
|
|
#define BDMICD_EFIDET 0x04 /* setting to 1 will pull LED feedback low */
|
|
#define BDMICD_DCR_DIR 0x20 /* 0 -> drive data buffers, 1 -> data port tristate */
|
|
|
|
static int bdm_icd_led_status;
|
|
|
|
/*
|
|
* Jumper seems to be responsible for SW generated breakpoints according to
|
|
* P&E's user manual
|
|
*
|
|
* we assume a Rev. A cable, so ignore jumper setting
|
|
*
|
|
* Power detection is instable: depends heavily on PP internal
|
|
* pull-ups/downs to get low level when there is no power
|
|
*
|
|
*/
|
|
|
|
|
|
static status_bitset
|
|
bdm_icd_init(bdm_descr_t * descr)
|
|
{
|
|
status_bitset status;
|
|
unsigned char temp1, temp2;
|
|
|
|
bdm_icd_led_status = BDMICD_LED;
|
|
|
|
/* ensure data outputs are driven for BPP port configuration */
|
|
bdm_out_ctl(BDMICD_DCR_DIR*0,descr);
|
|
|
|
/* perform icd check */
|
|
bdm_out_data(BDMICD_STEP_OUT | BDMICD_DSCLK | BDMICD_RST_OUT, descr);
|
|
bdm_delay(bdm_min_dly);
|
|
temp1 = bdm_in_st(descr);
|
|
bdm_out_data(BDMICD_STEP_OUT | BDMICD_DSCLK | BDMICD_RST_OUT |
|
|
bdm_icd_led_status, descr);
|
|
bdm_delay(bdm_min_dly);
|
|
temp2 = bdm_in_st(descr);
|
|
if ((temp1 ^ temp2) & BDMICD_ICDDETECT) {
|
|
printk("bdm_icd_init: detected ICD interface\n");
|
|
}
|
|
|
|
/* force breakpoint */
|
|
bdm_delay(bdm_min_dly);
|
|
status = descr->getstatus(descr);
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_icd_init minor %d status %d\n",
|
|
descr->minor, status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static int
|
|
bdm_icd_deinit(bdm_descr_t * descr)
|
|
{
|
|
#if LP_PORT_RESTORE
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_icd_deinit: restoring %#x\n", descr->bdm_old_ctl);
|
|
}
|
|
bdm_out_ctl(descr->bdm_old_ctl, descr);
|
|
/* restore old control port settings */
|
|
#endif /* LP_PORT_RESTORE */
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
/* read status byte from statusport and translate into bitset */
|
|
static status_bitset
|
|
bdm_icd_getstatus(bdm_descr_t * descr)
|
|
{
|
|
unsigned char temp = bdm_in_st(descr);
|
|
|
|
if (bdm_debug_level > BDM_DEBUG_SOME) {
|
|
printk("bdm_icd_getstatus minor=%d res=%#x\n", descr->minor, temp);
|
|
}
|
|
if (bdm_sense) {
|
|
if (!(temp & BDMICD_PWR))
|
|
return BDM_TARGETPOWER;
|
|
}
|
|
return (temp & BDMICD_FREEZE ? BDM_TARGETSTOPPED : 0);
|
|
}
|
|
|
|
/* this routine is last resort one, it is able resyncronize with MCU,
|
|
when some spike on DSCLK has disturbed MCU */
|
|
static status_bitset
|
|
bdm_icd_resynchro(bdm_descr_t *descr)
|
|
{
|
|
int i;
|
|
descr->ser_clk(descr, BDM_NOP_CMD, 0); /* send NOP command */
|
|
descr->ser_clk(descr, BDM_NOP_CMD, 0); /* send NOP command */
|
|
descr->ser_clk(descr, BDM_NOP_CMD, 0); /* send NOP command */
|
|
i=17; /* maximal number disturb in bit shift */
|
|
while(i--)
|
|
{
|
|
if((bdm_in_st(descr) & BDMICD_DSO)) {
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_icd_resynchro minor=%d shift=%d\n",
|
|
descr->minor,16-i);
|
|
}
|
|
return BDM_FAULT_NOERROR; /* DSO becomes 0 => OK */
|
|
}
|
|
bdm_out_data(BDMICD_RST_OUT | BDMICD_OE | BDMICD_STEP_OUT,
|
|
descr); /* DSCLK=0 */
|
|
bdm_delay(bdm_norm_dly);
|
|
bdm_out_data(BDMICD_RST_OUT | BDMICD_OE | BDMICD_STEP_OUT |
|
|
BDMICD_DSCLK, descr); /* DSCLK=1 */
|
|
bdm_delay(bdm_norm_dly);
|
|
}
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME)
|
|
printk("bdm_icd_resynchro failed\n");
|
|
return -BDM_FAULT_UNKNOWN;
|
|
}
|
|
|
|
/* restart chip and stop on first execution fetch */
|
|
static int
|
|
bdm_icd_restart_chip(bdm_descr_t * descr)
|
|
{
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_icd_restart_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
bdm_out_data(BDMICD_DSCLK, descr);
|
|
bdm_delay(bdm_norm_dly+bdm_reset_dly);
|
|
return descr->stop_chip(descr);
|
|
}
|
|
|
|
|
|
/* stop running target */
|
|
static int
|
|
bdm_icd_stop_chip(bdm_descr_t * descr)
|
|
{
|
|
unsigned int bdm_ctr;
|
|
int return_value;
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_icd_stop_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
if ((bdm_in_st(descr)) & BDMICD_FREEZE)
|
|
{ /* already frozen, ensure no spikes on BKPT/DSCLK in bdm_ser_clk */
|
|
bdm_out_data(BDMICD_RST_OUT, descr);
|
|
bdm_delay(bdm_short_dly);
|
|
bdm_out_data(BDMICD_STEP_OUT | BDMICD_RST_OUT, descr);
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
return_value = -BDM_FAULT_UNKNOWN;
|
|
|
|
bdm_delay(bdm_min_dly+100);
|
|
#if 1 /* stop imediately */
|
|
bdm_out_data(BDMICD_RST_OUT, descr);
|
|
#else /* stop after this instruction */
|
|
bdm_out_data(BDMICD_DSCLK | BDMICD_RST_OUT, descr);
|
|
#endif
|
|
bdm_delay(bdm_min_dly+300);
|
|
|
|
|
|
|
|
for (bdm_ctr = BDM_WAITCNT; bdm_ctr; bdm_ctr--) {
|
|
if ((bdm_in_st(descr)) & BDMICD_FREEZE) {
|
|
return_value = BDM_FAULT_NOERROR; /* target is now halted */
|
|
break;
|
|
}
|
|
bdm_delay(bdm_min_dly);
|
|
}
|
|
|
|
#ifdef DEB_TIM
|
|
printk("bdm_icd_stop_chip: having waited for FREEZE %d loops\n",
|
|
BDM_WAITCNT-bdm_ctr);
|
|
#endif
|
|
|
|
if (!bdm_ctr) {
|
|
#if 1
|
|
bdm_out_data(BDMICD_RST_OUT | BDMICD_FORCE_BERR, descr);
|
|
#else
|
|
bdm_out_data(BDMICD_DSCLK | BDMICD_RST_OUT | BDMICD_FORCE_BERR, descr);
|
|
#endif
|
|
bdm_delay(bdm_min_dly);
|
|
for (bdm_ctr = BDM_WAITCNT; bdm_ctr; bdm_ctr--) {
|
|
if ((bdm_in_st(descr)) & BDMICD_FREEZE) {
|
|
return_value = BDM_FAULT_NOERROR; /* target is now halted */
|
|
break;
|
|
}
|
|
bdm_delay(bdm_min_dly);
|
|
}
|
|
#ifdef DEB_TIM
|
|
printk("bdm_icd_stop_chip: berr has been forced; wait time was: %d\n",
|
|
BDM_WAITCNT-bdm_ctr);
|
|
#endif
|
|
}
|
|
|
|
#if 1
|
|
bdm_out_data(BDMICD_RST_OUT, descr);
|
|
bdm_delay(bdm_short_dly);
|
|
bdm_out_data(BDMICD_RST_OUT | BDMICD_STEP_OUT, descr);
|
|
#else
|
|
bdm_out_data(BDMICD_DSCLK | BDMICD_RST_OUT | BDMICD_STEP_OUT, descr);
|
|
#endif
|
|
|
|
#ifdef DEB_TIM
|
|
printk("bdm_icd_stop_chip: forcing DSCLK RST STEP\n");
|
|
#endif
|
|
|
|
if (!bdm_ctr) {
|
|
bdm_error(-BDM_FAULT_RESPONSE);
|
|
return -BDM_FAULT_RESPONSE;
|
|
}
|
|
#ifdef BDM_TRY_RESYNCHRO
|
|
descr->resynchro(descr); /* tries to find correct 17 bit boundary */
|
|
#endif /* BDM_TRY_RESYNCHRO */
|
|
return return_value;
|
|
}
|
|
|
|
|
|
|
|
/* single stepping target mcu */
|
|
static int
|
|
bdm_icd_step_chip(bdm_descr_t * descr)
|
|
{
|
|
int tester;
|
|
unsigned short DataOut = (BDM_GO_CMD & 1 ? BDMICD_DSI : 0);
|
|
|
|
status_bitset bdm_stat = descr->getstatus(descr);
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_icd_step_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
/* first two conditions will not be detected on ICD... */
|
|
if (bdm_stat & BDM_TARGETRESET) {
|
|
bdm_error(-BDM_FAULT_RESET);
|
|
return -BDM_FAULT_RESET;
|
|
}
|
|
if (bdm_stat & BDM_TARGETNC) {
|
|
bdm_error(-BDM_FAULT_CABLE);
|
|
return -BDM_FAULT_CABLE;
|
|
}
|
|
if (bdm_stat & BDM_TARGETPOWER) {
|
|
bdm_error(-BDM_FAULT_POWER);
|
|
return -BDM_FAULT_POWER;
|
|
}
|
|
tester = descr->ser_clk(descr, BDM_GO_CMD, 1);
|
|
switch (tester) {
|
|
case -BDM_FAULT_RESET:
|
|
case -BDM_FAULT_CABLE:
|
|
case -BDM_FAULT_POWER:
|
|
return tester;
|
|
}
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("stepchip sent: %x got : %x\n",
|
|
BDM_GO_CMD, (unsigned int) tester);
|
|
printk("last answerbit : %x\n", !(bdm_in_st(descr) & BDMICD_DSO));
|
|
}
|
|
bdm_out_data(BDMICD_OE | BDMICD_STEP_OUT | DataOut | BDMICD_RST_OUT, descr);
|
|
bdm_delay(bdm_norm_dly);
|
|
bdm_out_data(BDMICD_OE | DataOut | BDMICD_RST_OUT, descr);
|
|
bdm_delay(bdm_min_dly);
|
|
bdm_out_data(BDMICD_DSCLK | DataOut | BDMICD_RST_OUT, descr);
|
|
|
|
#ifdef BDM_TRY_RESYNCHRO
|
|
descr->stop_chip(descr);
|
|
return descr->resynchro(descr);
|
|
#else /* BDM_TRY_RESYNCHRO */
|
|
return descr->stop_chip(descr);
|
|
#endif /* BDM_TRY_RESYNCHRO */
|
|
}
|
|
|
|
/* reset target chip without asserting freeze */
|
|
static int
|
|
bdm_icd_release_chip(bdm_descr_t * descr)
|
|
{
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_icd_release_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
bdm_out_data(BDMICD_DSCLK | BDMICD_STEP_OUT, descr);
|
|
bdm_delay(bdm_norm_dly);
|
|
bdm_out_data(BDMICD_DSCLK | BDMICD_RST_OUT | BDMICD_STEP_OUT, descr);
|
|
bdm_delay(bdm_short_dly);
|
|
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
/*
|
|
* Restart chip, enable background debugging mode, halt on first fetch
|
|
*
|
|
* The software from the Motorola BBS tries to have the target
|
|
* chip begin execution, but that doesn't work very reliably.
|
|
* The RESETH* line rises rather slowly, so sometimes the BKPT* / DSCLK
|
|
* would be seen low, and sometimes it wouldn't.
|
|
*/
|
|
static int
|
|
bdm_icd_reset_chip(bdm_descr_t * descr)
|
|
{
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_icd_reset_chip minor=%d\n", descr->minor);
|
|
}
|
|
|
|
/* this is according to Scott Howard */
|
|
bdm_out_data(BDMICD_DSCLK | BDMICD_STEP_OUT, descr);
|
|
bdm_delay(bdm_norm_dly+bdm_reset_dly);
|
|
bdm_out_data(BDMICD_DSCLK | BDMICD_STEP_OUT | BDMICD_RST_OUT, descr);
|
|
bdm_delay(bdm_norm_dly+bdm_reset_dly);
|
|
|
|
/*
|
|
*Tom Hoover's Error or Optimization? has to be checked
|
|
* FIXME... with scope; kick out if unnecessary.
|
|
*/
|
|
bdm_out_data(BDMICD_DSCLK, descr);
|
|
bdm_delay(bdm_norm_dly+1000);
|
|
/*
|
|
descr->stop_chip(descr);
|
|
*/
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
/* serial software protokoll for bdm-icd-interface */
|
|
static int
|
|
bdm_icd_ser_clk(bdm_descr_t * descr, short bdm_value, int delay_bits)
|
|
{
|
|
unsigned int ShiftRegister;
|
|
unsigned char DataOut;
|
|
unsigned counter;
|
|
unsigned bdm_stat = descr->getstatus(descr);
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("icd_ser_clk: in-val %x delay %d\n",
|
|
(unsigned short) bdm_value, delay_bits);
|
|
}
|
|
|
|
ShiftRegister = bdm_value;
|
|
ShiftRegister <<= BITS;
|
|
/* first two conditions will not be detected on ICD... */
|
|
if (bdm_stat & BDM_TARGETRESET) { /*error checking */
|
|
bdm_error(-BDM_FAULT_RESET);
|
|
return -BDM_FAULT_RESET;
|
|
}
|
|
if (bdm_stat & BDM_TARGETNC) {
|
|
bdm_error(-BDM_FAULT_CABLE);
|
|
return -BDM_FAULT_CABLE;
|
|
}
|
|
if (bdm_stat & BDM_TARGETPOWER) {
|
|
bdm_error(-BDM_FAULT_POWER);
|
|
return -BDM_FAULT_POWER;
|
|
}
|
|
if(!(bdm_stat & BDM_TARGETSTOPPED))
|
|
{ if (bdm_debug_level >= BDM_DEBUG_SOME)
|
|
printk("bdm_ser_clk stop target first minor=%d\n", descr->minor);
|
|
if(descr->stop_chip(descr)==-BDM_FAULT_RESPONSE)
|
|
{ printk("bdm_ser_clk can't stop it minor=%d\n", descr->minor);
|
|
return -BDM_FAULT_RESPONSE;
|
|
}
|
|
}
|
|
if(bdm_no_ser_dly_mode && (delay_bits&SER_CLK_DSO_WAIT))
|
|
{ /* Wait for DSO to become 0 to indicate ready
|
|
* according CPU32UM, DSO is updated as long as
|
|
* DSCLK is high
|
|
*/
|
|
int wait_cnt;
|
|
for(wait_cnt=0;wait_cnt<100;wait_cnt++)
|
|
{ if (bdm_in_st(descr) & BDMICD_DSO)
|
|
break; /* DSO becomed zerro already */
|
|
bdm_delay(bdm_min_dly);
|
|
}
|
|
if(wait_cnt && (bdm_debug_level >= BDM_DEBUG_SOME))
|
|
printk("bdm_icd_ser_clk: ready after %d cycles\n",
|
|
wait_cnt);
|
|
}
|
|
|
|
counter = 32 - BITS - (delay_bits&0xff);
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("bdm_icd_ser_clk: writing %x\n", bdm_value);
|
|
}
|
|
while (counter--) {
|
|
DataOut = ((ShiftRegister & 0x80000000) ? BDMICD_DSI : 0);
|
|
/*if 1 then DSI=1*/
|
|
bdm_out_data(DataOut | BDMICD_RST_OUT | BDMICD_OE | BDMICD_STEP_OUT |
|
|
BDMICD_LED, descr); /* DSCLK=0 */
|
|
if(!bdm_no_ser_dly_mode)
|
|
bdm_delay(bdm_norm_dly);
|
|
|
|
ShiftRegister <<= 1; /*shift one bit left*/
|
|
if (!(bdm_in_st(descr) & BDMICD_DSO))
|
|
ShiftRegister |= 1; /*put 1 on 0.bit */
|
|
bdm_out_data(DataOut | BDMICD_RST_OUT | BDMICD_OE | BDMICD_STEP_OUT |
|
|
BDMICD_DSCLK | BDMICD_LED, descr); /* DSCLK=1 */
|
|
if(!bdm_no_ser_dly_mode)
|
|
bdm_delay(bdm_half_dly);
|
|
}
|
|
if ((delay_bits&0xff) == 0) {
|
|
bdm_out_data(BDMICD_DSCLK | BDMICD_STEP_OUT | BDMICD_RST_OUT,
|
|
descr);
|
|
bdm_delay(bdm_min_dly);
|
|
}
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("icd_ser_clk: out-val %x delay %d\n",
|
|
(unsigned short) ShiftRegister, delay_bits);
|
|
}
|
|
|
|
|
|
#ifdef FIXME
|
|
if (!(delay_bits&0xff) && (ShiftRegister & 0x10000)) switch (ShiftRegister) {
|
|
case 0x1ffff: /* no valid command return */
|
|
return -BDM_FAULT_NVC;
|
|
case 0x10001:
|
|
return -BDM_FAULT_BERR;
|
|
case 0x10000:
|
|
return BDM_NOTE_NOTREADY;
|
|
default: ;
|
|
}
|
|
#endif /* FIXME */
|
|
return ShiftRegister;
|
|
}
|
|
|
|
/* switch LED if available */
|
|
static int
|
|
bdm_icd_setled(bdm_descr_t * descr, int switchstate)
|
|
{
|
|
bdm_icd_led_status = (switchstate ? BDMICD_LED : 0);
|
|
bdm_out_data(BDMICD_STEP_OUT | BDMICD_DSCLK | BDMICD_RST_OUT |
|
|
bdm_icd_led_status, descr);
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
#endif
|
|
|
|
static int bdm_minor_index[] = {
|
|
#ifdef PD_INTERFACE
|
|
0, 1, 2,
|
|
#else
|
|
-1, -1, -1,
|
|
#endif
|
|
-1,
|
|
#ifdef ICD_INTERFACE
|
|
3, 4, 5,
|
|
#else
|
|
-1, -1, -1,
|
|
#endif
|
|
-1,
|
|
#ifdef AS_INTERFACE
|
|
-1, -1, -1,
|
|
#else
|
|
-1, -1, -1,
|
|
#endif
|
|
-1
|
|
};
|
|
const int bdm_minor_index_size =
|
|
sizeof(bdm_minor_index)/sizeof(*bdm_minor_index);
|
|
|
|
#define PD_DESCRIPTOR(adr,minor,name) \
|
|
BDM_DESCR_MAGIC, adr, minor, \
|
|
bdm_pd_init, bdm_pd_deinit, bdm_pd_getstatus,\
|
|
bdm_pd_restart_chip, bdm_pd_release_chip, bdm_pd_stop_chip,\
|
|
bdm_pd_step_chip, bdm_pd_reset_chip, bdm_pd_ser_clk,\
|
|
bdm_pd_setled, bdm_pd_resynchro , name
|
|
|
|
#define ICD_DESCRIPTOR(adr,minor,name) \
|
|
BDM_DESCR_MAGIC, adr, minor, \
|
|
bdm_icd_init, bdm_icd_deinit, bdm_icd_getstatus,\
|
|
bdm_icd_restart_chip, bdm_icd_release_chip, bdm_icd_stop_chip,\
|
|
bdm_icd_step_chip, bdm_icd_reset_chip, bdm_icd_ser_clk,\
|
|
bdm_icd_setled, bdm_icd_resynchro , name
|
|
|
|
#define EMPTY_DESCRIPTOR(adr,minor) \
|
|
0, adr, minor, \
|
|
NULL, NULL, NULL, \
|
|
NULL, NULL, NULL, \
|
|
NULL, NULL, NULL, \
|
|
NULL, NULL, NULL
|
|
|
|
static bdm_descr_t bdm_driver_descriptors[] = {
|
|
#ifdef PD_INTERFACE
|
|
{ PD_DESCRIPTOR(PORT_ADDRESSE_LP1,0,"pd0") },
|
|
{ PD_DESCRIPTOR(PORT_ADDRESSE_LP2,1,"pd1") },
|
|
{ PD_DESCRIPTOR(PORT_ADDRESSE_LP3,2,"pd2") },
|
|
#else
|
|
{ EMPTY_DESCRIPTOR(0,0) },
|
|
{ EMPTY_DESCRIPTOR(0,1) },
|
|
{ EMPTY_DESCRIPTOR(0,2) },
|
|
#endif
|
|
#ifdef ICD_INTERFACE
|
|
{ ICD_DESCRIPTOR(PORT_ADDRESSE_LP1,4,"icd0") },
|
|
{ ICD_DESCRIPTOR(PORT_ADDRESSE_LP2,5,"icd1") },
|
|
{ ICD_DESCRIPTOR(PORT_ADDRESSE_LP3,6,"icd2") },
|
|
#else
|
|
{ EMPTY_DESCRIPTOR(0,4) },
|
|
{ EMPTY_DESCRIPTOR(0,5) },
|
|
{ EMPTY_DESCRIPTOR(0,6) },
|
|
#endif
|
|
{ EMPTY_DESCRIPTOR(0,8) },
|
|
{ EMPTY_DESCRIPTOR(0,9) },
|
|
{ EMPTY_DESCRIPTOR(0,10) }
|
|
};
|
|
|
|
/* preparation macros to get minor descriptor */
|
|
|
|
#define check_descriptor(rdev, descr) \
|
|
{\
|
|
unsigned int minor; int descr_indx;\
|
|
if ((minor = kc_dev2minor(rdev)) > bdm_minor_index_size) {\
|
|
return -ENODEV;\
|
|
} \
|
|
if ((descr_indx = bdm_minor_index[minor]) < 0) {\
|
|
return -ENODEV;\
|
|
}\
|
|
descr = &bdm_driver_descriptors[descr_indx];\
|
|
if (descr->minor != minor) {\
|
|
printk("Inconsistency: descr->minor %d, minor %d\n", descr->minor,\
|
|
minor);\
|
|
return -ENODEV;\
|
|
}\
|
|
}
|
|
|
|
#define minor2descriptor(minor) \
|
|
(&bdm_driver_descriptors[bdm_minor_index[(minor)]])
|
|
|
|
static bdm_descr_t *bdm_file2descr(const struct file *file)
|
|
{
|
|
bdm_descr_t *descr = (bdm_descr_t *)(file->private_data);
|
|
if(descr==NULL){
|
|
printk(KERN_CRIT "BDM no descriptor!!!\n");
|
|
return NULL;
|
|
}
|
|
if(descr->magic!=BDM_DESCR_MAGIC){
|
|
printk(KERN_CRIT "BDM wrong MAGIC number!!!\n");
|
|
return NULL;
|
|
}
|
|
return descr;
|
|
}
|
|
|
|
static int
|
|
bdm_open(struct inode *inode, struct file *file)
|
|
{
|
|
status_bitset bdm_okay;
|
|
bdm_descr_t *descr;
|
|
int val;
|
|
#ifdef WITH_PARPORT_SUPPORT
|
|
static struct pardevice *parport;
|
|
#endif /* WITH_PARPORT_SUPPORT */
|
|
|
|
|
|
check_descriptor(inode->i_rdev, descr);
|
|
|
|
#ifndef WITH_PARPORT_SUPPORT
|
|
if (check_region(BDM_DATA(descr), 3)) {
|
|
printk("bdm_open: address space in use (conflict with PARPORT ?)...\n");
|
|
return -EBUSY;
|
|
request_region(BDM_DATA(descr), 3, "bdm");
|
|
}
|
|
#else /* WITH_PARPORT_SUPPORT */
|
|
parport=bdm_get_parport(descr);
|
|
if(!parport)
|
|
return -ENODEV;
|
|
if(parport_claim(parport)) {
|
|
printk("bdm_open: no access to PARPORT device");
|
|
return -EBUSY;
|
|
}
|
|
#endif /* WITH_PARPORT_SUPPORT */
|
|
/* stupid test if required port is really available */
|
|
val=bdm_in_data(descr);
|
|
val&=~0x21;
|
|
bdm_out_data(val, descr);
|
|
if (bdm_in_data(descr) != val) {
|
|
printk("bdm_open: physical device not detected...\n");
|
|
#ifdef WITH_PARPORT_SUPPORT
|
|
parport_release(bdm_get_parport(descr));
|
|
#else
|
|
release_region(BDM_DATA(descr), 3);
|
|
#endif
|
|
return -ENODEV;
|
|
}
|
|
|
|
kc_MOD_INC_USE_COUNT;
|
|
|
|
file->private_data=descr;
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_open\n");
|
|
}
|
|
|
|
bdm_okay = descr->init(descr);
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
if (!(bdm_okay & BDM_TARGETNC)) {
|
|
printk("BDM detected !!\n");
|
|
} else {
|
|
printk("Target not connected ! Error %d \n", bdm_okay);
|
|
}
|
|
}
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_open successful\n");
|
|
}
|
|
|
|
return BDM_FAULT_NOERROR;
|
|
}
|
|
|
|
static CLOSERET
|
|
bdm_release(struct inode *inode, struct file *file)
|
|
{
|
|
bdm_descr_t *descr = bdm_file2descr(file);
|
|
if(!descr) return -ENODEV;
|
|
|
|
descr->deinit(descr);
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_release\n");
|
|
}
|
|
|
|
file->private_data=NULL;
|
|
kc_MOD_DEC_USE_COUNT;
|
|
#ifdef WITH_PARPORT_SUPPORT
|
|
parport_release(bdm_get_parport(descr));
|
|
#else
|
|
release_region(BDM_DATA(descr), 3);
|
|
#endif
|
|
return (CLOSERET)0;
|
|
}
|
|
|
|
static int
|
|
bdm_ioctl(struct inode *inode, struct file *file,
|
|
unsigned int cmd, unsigned long arg)
|
|
{
|
|
unsigned retval = BDM_FAULT_NOERROR;
|
|
status_bitset status;
|
|
bdm_descr_t *descr = bdm_file2descr(file);
|
|
if(!descr) return -ENODEV;
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_ioctl minor=%d cmd=%d (%s) arg=0x%lx\n",
|
|
descr->minor, cmd, bdm_get_ioctl_name(cmd), arg);
|
|
}
|
|
switch (cmd) {
|
|
case BDM_INIT:
|
|
status = descr->init(descr);
|
|
if (status & BDM_TARGETNC)
|
|
retval = -BDM_FAULT_CABLE;
|
|
else if (status & BDM_TARGETPOWER)
|
|
retval = -BDM_FAULT_POWER;
|
|
break;
|
|
case BDM_DEINIT:
|
|
retval = descr->deinit(descr);
|
|
break;
|
|
case BDM_RESET_CHIP:
|
|
retval = descr->reset_chip(descr);
|
|
/* hardware reset on MCU - running state */
|
|
break;
|
|
case BDM_RESTART_CHIP:
|
|
/* reset target and stops execution on first instruction fetch */
|
|
retval = descr->restart_chip(descr);
|
|
break;
|
|
case BDM_STOP_CHIP:
|
|
/* stop running target (FREEZE) */
|
|
retval = descr->stop_chip(descr);
|
|
break;
|
|
case BDM_STEP_CHIP:
|
|
/* one step on target */
|
|
descr->step_chip(descr);
|
|
retval = BDM_FAULT_NOERROR;
|
|
break;
|
|
case BDM_GET_STATUS:
|
|
retval = descr->getstatus(descr);
|
|
break;
|
|
case BDM_SPEED:
|
|
/* Change speed value */
|
|
if ((int) arg <= 0) {
|
|
if(bdm_debug_level >= BDM_DEBUG_SOME)
|
|
printk("bdm_ioctl BDM_SPEED: no_ser_dly_mode=1\n");
|
|
bdm_no_ser_dly_mode = 1;
|
|
bdm_norm_dly = 1;
|
|
} else {
|
|
bdm_no_ser_dly_mode = 0;
|
|
bdm_norm_dly = (int) arg;
|
|
}
|
|
bdm_long_dly = BDM_LONG_DLY(bdm_norm_dly);
|
|
bdm_half_dly = BDM_HALF_DLY(bdm_norm_dly);
|
|
bdm_short_dly = BDM_SHORT_DLY(bdm_norm_dly);
|
|
bdm_min_dly = BDM_MIN_DLY(bdm_norm_dly);
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_ioctl SPEED: "
|
|
"norm %d long %d half %d short %d min %d\n",
|
|
bdm_norm_dly, bdm_long_dly, bdm_half_dly, bdm_short_dly,
|
|
bdm_min_dly);
|
|
}
|
|
break;
|
|
case BDM_RELEASE_CHIP:
|
|
/* reset without bdm, so quit bdm mode */
|
|
retval = descr->release_chip(descr);
|
|
break;
|
|
case BDM_DEBUG_LEVEL:
|
|
/* change debug level 0,1,2 */
|
|
if (arg < 3) {
|
|
bdm_debug_level = (unsigned int) arg;
|
|
} else {
|
|
retval = -EINVAL;
|
|
}
|
|
break;
|
|
case BDM_GET_VERSION:
|
|
/* read counter and return it to *arg */
|
|
if(kc_put_user_long(bdm_version, arg))
|
|
retval = -EINVAL;
|
|
break;
|
|
case BDM_SENSECABLE:
|
|
bdm_sense = arg;
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_ioctl: setting bdm_sense to %d\n", bdm_sense);
|
|
}
|
|
break;
|
|
case BDM_RESPW:
|
|
/* reset additional delay */
|
|
bdm_reset_dly = (unsigned int) arg;
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_ioctl: setting reset_pw to %d\n", bdm_reset_dly);
|
|
}
|
|
break;
|
|
case BDM_SETLED:
|
|
retval = descr->set_led(descr,arg);
|
|
break;
|
|
#ifdef EFIICDISP
|
|
|
|
#define BDMICD_ispSCLK 1 /* ctrl-Register; clock data to isp */
|
|
#define BDMICD_ispSDI 8 /* ctrl-Register; data line to isp */
|
|
#define BDMICD_ispMODE 0x80 /* data-Register; mode for ips */
|
|
#define BDMICD_ispSDO 0x20 /* stat-Register; data line from isp */
|
|
case BDM_ISPSET:
|
|
{
|
|
static char ispcmd=0, ispdata=0;
|
|
switch(arg & 0xf) {
|
|
case BDM_ispSDI:
|
|
/* #define ISPVERBOSE 1 */
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("ispSDI ");
|
|
}
|
|
if (arg & BDM_isp_LEVEL) { /* neg. output */
|
|
ispcmd &= ~BDMICD_ispSDI;
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("1\n");
|
|
}
|
|
} else {
|
|
ispcmd |= BDMICD_ispSDI;
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("0\n");
|
|
}
|
|
}
|
|
bdm_out_ctl(ispcmd, descr);
|
|
break;
|
|
case BDM_ispSCLK:
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("ispSCLK ");
|
|
}
|
|
if (arg & BDM_isp_LEVEL) { /* neg. output */
|
|
ispcmd &= ~BDMICD_ispSCLK;
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("1\n");
|
|
}
|
|
} else {
|
|
ispcmd |= BDMICD_ispSCLK;
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("0\n");
|
|
}
|
|
}
|
|
bdm_out_ctl(ispcmd, descr);
|
|
break;
|
|
case BDM_ispMODE:
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("ispMODE ");
|
|
}
|
|
if (arg & BDM_isp_LEVEL) {
|
|
ispdata |= BDMICD_ispMODE;
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("1\n");
|
|
}
|
|
} else {
|
|
ispdata &= ~BDMICD_ispMODE;
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("0\n");
|
|
}
|
|
}
|
|
bdm_out_data(ispdata, descr);
|
|
break;
|
|
case BDM_ispISP:
|
|
/* ignore */
|
|
break;
|
|
}
|
|
udelay(100);
|
|
/* this is necessary to mimic the bdm_delay factor for isp */
|
|
break;
|
|
}
|
|
case BDM_ISPGET:
|
|
if (bdm_in_st(descr) & BDMICD_ispSDO) {
|
|
retval = 1;
|
|
} else {
|
|
retval = 0;
|
|
}
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("ispSDO %d\n", retval);
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
retval = -EINVAL;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
static RWRET
|
|
bdm_write(WRITE_PARAMETERS)
|
|
{
|
|
short bdm_word;
|
|
int ret;
|
|
int written = 0;
|
|
bdm_descr_t *descr = bdm_file2descr(file);
|
|
if(!descr) return -ENODEV;
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_write minor %d len %d\n", descr->minor, (int)count);
|
|
}
|
|
if (!access_ok(VERIFY_READ, buf, count))
|
|
return -EINVAL;
|
|
|
|
while (count > 0) {
|
|
bdm_word = 0;
|
|
kc_get_user_word(bdm_word, buf);
|
|
ret = descr->ser_clk(descr, bdm_word, 0);
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("bdm_write sent: %x received: %x\n",
|
|
bdm_word, (unsigned int) ret);
|
|
}
|
|
if (written) {
|
|
switch (ret) {
|
|
case 0x1ffff: /* no valid command return */
|
|
return -BDM_FAULT_NVC;
|
|
case 0x10001: /* Buserror */
|
|
return -BDM_FAULT_BERR;
|
|
case -BDM_FAULT_RESET:
|
|
case -BDM_FAULT_CABLE:
|
|
case -BDM_FAULT_POWER:
|
|
return ret;
|
|
}
|
|
}
|
|
count -= 2;
|
|
buf += 2;
|
|
written += 2;
|
|
if (!(written % BYTECOUNT_FOR_BEING_NICE)) {
|
|
schedule();
|
|
}
|
|
}
|
|
return written;
|
|
}
|
|
|
|
static RWRET
|
|
bdm_read(READ_PARAMETERS)
|
|
{
|
|
short bdm_word = BDM_NOP_CMD, value;
|
|
int ret;
|
|
int read = 0, timeout = 0;
|
|
bdm_descr_t *descr = bdm_file2descr(file);
|
|
if(!descr) return -ENODEV;
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_SOME) {
|
|
printk("bdm_read minor=%d len=%d\n", descr->minor, (int)count);
|
|
}
|
|
if (!access_ok(VERIFY_WRITE, buf, count))
|
|
return -EINVAL;
|
|
|
|
while (count > 0) {
|
|
ret = descr->ser_clk(descr, bdm_word, SER_CLK_DSO_WAIT);
|
|
|
|
if (bdm_debug_level >= BDM_DEBUG_ALL) {
|
|
printk("\n read sent: %x received: %x\n",
|
|
bdm_word, (unsigned int) ret);
|
|
}
|
|
switch (ret) {
|
|
case 0x10001: /* test if BERR*/
|
|
return -BDM_FAULT_BERR;
|
|
case 0x1ffff: /* no valid command return */
|
|
return -BDM_FAULT_NVC;
|
|
case 0x10000:
|
|
timeout++;
|
|
if (timeout - read / 2 > 4) {
|
|
/*
|
|
* we assume the FAULT_RESPONSE error, if number of
|
|
* failed attempts is by 4 higher than number of
|
|
* successful attempts
|
|
*/
|
|
return -BDM_FAULT_RESPONSE;
|
|
}
|
|
break;
|
|
case -BDM_FAULT_RESET:
|
|
case -BDM_FAULT_CABLE:
|
|
case -BDM_FAULT_POWER:
|
|
return ret;
|
|
default:
|
|
value = ret;
|
|
kc_put_user_word(value, buf);
|
|
buf += 2;
|
|
count -= 2;
|
|
read += 2;
|
|
if (!(read % BYTECOUNT_FOR_BEING_NICE)) {
|
|
schedule();
|
|
}
|
|
}
|
|
|
|
}
|
|
return read;
|
|
}
|
|
|
|
/* static struct file_operations bdm_fops */
|
|
KC_CHRDEV_FOPS_BEG(bdm_fops)
|
|
KC_FOPS_LSEEK(NULL) /* lseek */
|
|
read:bdm_read, /* read */
|
|
write:bdm_write, /* write */
|
|
readdir:NULL, /* readdir */
|
|
poll:NULL, /* poll/select */
|
|
ioctl:bdm_ioctl, /* ioctl */
|
|
mmap:NULL, /* mmap */
|
|
open:bdm_open, /* open */
|
|
KC_FOPS_FLUSH(NULL) /* flush */
|
|
KC_FOPS_RELEASE(bdm_release) /* release */
|
|
fsync:NULL, /* fsync */
|
|
fasync:NULL, /* fasync */
|
|
NULL, /* check_media_change */
|
|
NULL, /* revalidate */
|
|
KC_CHRDEV_FOPS_END;
|
|
|
|
struct kc_class *bdm_class;
|
|
|
|
#ifdef WITH_PARPORT_SUPPORT
|
|
static int
|
|
bdm_preempt(void *handle)
|
|
{
|
|
return 1; // 1=don't release parport
|
|
}
|
|
#endif
|
|
|
|
|
|
int
|
|
init_module(void)
|
|
{
|
|
int i;
|
|
#ifdef WITH_PARPORT_SUPPORT
|
|
int num;
|
|
struct parport *port;
|
|
int num_offset=0;
|
|
#endif
|
|
|
|
printk("BDM init_module\n %s\n %s\n %s\n",
|
|
"$RCSfile: bdm.c,v $", "$Revision: 1.8 $", "$Date: 2006/12/28 13:04:58 $");
|
|
/*"$Id: bdm.c,v 1.8 2006/12/28 13:04:58 ppisa Exp $", */
|
|
printk(" Version %s\n Compiled at %s %s\n",
|
|
#ifdef PD_INTERFACE
|
|
"PD "
|
|
#endif
|
|
#ifdef ICD_INTERFACE
|
|
"ICD "
|
|
#ifdef EFIICDISP
|
|
"+ISP"
|
|
#endif
|
|
" "
|
|
#endif
|
|
"", __DATE__, __TIME__);
|
|
|
|
#ifdef WITH_PARPORT_SUPPORT
|
|
printk("BDM init_module: compiled with PARPORT support\n");
|
|
for(num=0; num < MAX_BDM_PORTS; num++)
|
|
{
|
|
port=NULL;
|
|
do{
|
|
if(num+num_offset >= PARPORT_MAX) break;
|
|
port=parport_find_number(num+num_offset);
|
|
if(port) break;
|
|
num_offset++;
|
|
}while(1);
|
|
if(!port) break;
|
|
bdm_parports[num] = parport_register_device(port, "bdm", bdm_preempt, NULL, NULL,0,NULL);
|
|
if (!bdm_parports[num]){
|
|
printk("BDM init_module: Can't register device no.: %d",num);
|
|
}
|
|
parport_put_port(port);
|
|
}
|
|
#endif
|
|
|
|
#ifndef BDM_WITH_DEVFS
|
|
if (register_chrdev(BDM_MAJOR_NUMBER, "bdm", &bdm_fops)) {
|
|
printk("Unable to get major number for BDM driver\n");
|
|
return -EIO;
|
|
}
|
|
#else /* BDM_WITH_DEVFS */
|
|
if (devfs_register_chrdev(BDM_MAJOR_NUMBER, "bdm", &bdm_fops)) {
|
|
printk("Unable to get major number for BDM driver\n");
|
|
return -EIO;
|
|
}
|
|
/* I hate next conditional compilation, but k_compat.h can not handle
|
|
latest changes to devfs done by Adam J. Richter <adam@yggdrasil.com>. */
|
|
#if (LINUX_VERSION_CODE >= VERSION(2,5,60))
|
|
#if (LINUX_VERSION_CODE < VERSION(2,6,17))
|
|
devfs_mk_dir (BDM_DEVFS_DIR_NAME);
|
|
#endif /* < 2.6.17 */
|
|
bdm_class = kc_class_create(THIS_MODULE, BDM_DEVFS_DIR_NAME);
|
|
for(i=0;i<bdm_minor_index_size;i++){
|
|
/*char dev_name[32];*/
|
|
if(bdm_minor_index[i]<0) continue;
|
|
if(!minor2descriptor(i)->name) continue;
|
|
/*sprintf(dev_name, "%s/%s", BDM_DEVFS_DIR_NAME, minor2descriptor(i)->name);*/
|
|
#if (LINUX_VERSION_CODE < VERSION(2,6,17))
|
|
devfs_mk_cdev(MKDEV(BDM_MAJOR_NUMBER, i), S_IFCHR | S_IRUGO | S_IWUGO,
|
|
"%s/%s", BDM_DEVFS_DIR_NAME, minor2descriptor(i)->name);
|
|
#endif /* < 2.6.17 */
|
|
kc_class_device_create(bdm_class, NULL, MKDEV(BDM_MAJOR_NUMBER, i), NULL, minor2descriptor(i)->name);
|
|
}
|
|
#else /* < 2.5.60 */
|
|
bdm_devfs_handle = devfs_mk_dir (NULL, BDM_DEVFS_DIR_NAME, NULL);
|
|
for(i=0;i<bdm_minor_index_size;i++){
|
|
if(bdm_minor_index[i]<0) continue;
|
|
if(!minor2descriptor(i)->name) continue;
|
|
devfs_register(bdm_devfs_handle, minor2descriptor(i)->name,
|
|
DEVFS_FL_DEFAULT, BDM_MAJOR_NUMBER, i,
|
|
S_IFCHR | S_IRUGO | S_IWUGO ,
|
|
&bdm_fops, NULL);
|
|
}
|
|
#endif /* 2.5.60 */
|
|
#endif /* BDM_WITH_DEVFS */
|
|
printk("BDM driver succesfully registered !!\n");
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
cleanup_module(void)
|
|
{
|
|
#ifdef WITH_PARPORT_SUPPORT
|
|
int num;
|
|
#endif
|
|
|
|
#ifdef WITH_PARPORT_SUPPORT
|
|
printk("BDM init_module: compiled with PARPORT support\n");
|
|
for(num=0; num < MAX_BDM_PORTS; num++)
|
|
{
|
|
if (bdm_parports[num])
|
|
parport_unregister_device(bdm_parports[num]);
|
|
bdm_parports[num] = NULL;
|
|
}
|
|
#endif
|
|
#ifdef BDM_WITH_DEVFS
|
|
/* I hate next conditional compilation, but k_compat.h can not handle
|
|
latest changes to devfs done by Adam J. Richter <adam@yggdrasil.com>. */
|
|
#if (LINUX_VERSION_CODE >= VERSION(2,5,60))
|
|
{
|
|
int i;
|
|
for(i=0;i<bdm_minor_index_size;i++){
|
|
if(bdm_minor_index[i]<0) continue;
|
|
if(!minor2descriptor(i)->name) continue;
|
|
kc_class_device_destroy(bdm_class, MKDEV(BDM_MAJOR_NUMBER, i));
|
|
#if (LINUX_VERSION_CODE < VERSION(2,6,17))
|
|
devfs_remove("%s/%s", BDM_DEVFS_DIR_NAME, minor2descriptor(i)->name);
|
|
#endif /* < 2.6.17 */
|
|
}
|
|
}
|
|
#if (LINUX_VERSION_CODE < VERSION(2,6,17))
|
|
devfs_remove(BDM_DEVFS_DIR_NAME);
|
|
#endif /* < 2.6.17 */
|
|
kc_class_destroy(bdm_class);
|
|
#else /* < 2.5.60 */
|
|
if(bdm_devfs_handle)
|
|
devfs_unregister (bdm_devfs_handle);
|
|
#endif /* < 2.5.60 */
|
|
if (devfs_unregister_chrdev(BDM_MAJOR_NUMBER, "bdm") != 0)
|
|
#else /* BDM_WITH_DEVFS */
|
|
if (unregister_chrdev(BDM_MAJOR_NUMBER, "bdm") != 0)
|
|
#endif /* BDM_WITH_DEVFS */
|
|
printk("BDM cleanup: Unregister failed\n");
|
|
else
|
|
printk("BDM cleanup: Unregister O.K.\n");
|
|
}
|