/* * Motorola Background Debug Mode Driver * Copyright (C) 2000 James Housley * Copyright (C) 2000 Chris Johns * * 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. * * FreeBSD support by: (Started May 9, 2000) * James Housley * The Housleys dot Net * 65 Frank's Lane * Hanover, MA 02339, USA * * jim@thehousleys.net * * Chris Johns & Greg Tunnock * Redfern Broadband Networks. * Continued FreeBSD port, Sep 2000 * This porting effort has been made possible by Redfern Broadband * Networks. * * ccj@acm.org * */ #define BDM_DEFAULT_DEBUG 0 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* ************************************************************************ * OpenBSD Driver Structures * ************************************************************************ */ #define UNIT(d) ((unsigned int)(minor(d) & 0x07)) /* ************************************************************************ * UNIX driver support routines * ************************************************************************ */ /* * Function prototypes. */ static int init_module (void); static void os_lock_module (void); static void os_unlock_module (void); static int bdmprobe (void); static void bdmattach (void); static void bdmdetach (void); static void bdm_outb (int port, int value); /* * Delay for a while so target can keep up. */ static void bdm_delay (int counter) { while (counter--) { __asm volatile ("nop"); } } /* * Wait a longer while . */ static char BDMsleep; static void bdm_sleep (u_int time) { tsleep((void *)&BDMsleep, ((PZERO + 8)| PCATCH), "bdmslp", (int)time); } /* ************************************************************************ * OS worker functions. * ************************************************************************ */ static int os_claim_io_ports (char *name, unsigned int base, unsigned int num) { return 0; } static int os_release_io_ports (unsigned int base, unsigned int num) { return 0; } static int os_copy_in (void *dst, void *src, int size) { (void)memcpy(dst, src, (size_t)size); return 0; } static int os_copy_out (void *dst, void *src, int size) { (void)memcpy(dst, src, (size_t)size); return 0; } /** * Moves data from user-space address to kernel-space address. * * This is provide for Operating Systems with separate move and copy * strategies. If an OS doesn't have a move strategy this function will * be the same as os_copy_in(). * * Param dst Kernel-space address to copy to. * Param src User-space address to copy from. * Param size Number of bytes to copy. * * Returns 0 if successful. */ static int os_move_in (void *dst, void *src, int size) { return uiomove((caddr_t)dst, size, (struct uio *)src); } #define BUF_INCREMENTED_BY_MOVE_IN /** * Moves data from kernel-space address to user-space address. * * This is provide for Operating Systems with separate move and copy * strategies. If an OS doesn't have a move strategy this function will * be the same as os_copy_out(). * * Param dst User-space address to copy to. * Param src Kernel-space address to copy from. * Param size Number of bytes to copy. * * Returns 0 if successful. */ static int os_move_out (void *dst, void *src, int size) { return uiomove((caddr_t)src, size, (struct uio *)dst); } #define BUF_INCREMENTED_BY_MOVE_OUT static void os_lock_module () { } static void os_unlock_module () { } /* * Big hack to get around differences in outb */ static void bdm_outb (int port, int value) { outb (port, value); } #undef outb #define outb(value, port) bdm_outb (port, value) /* ************************************************************************ * Mappings to OpenBSD * ************************************************************************ */ #define PRINTF printf #define udelay(x) DELAY (x) #define MINOR(x) minor (x) #define HZ hz /* ************************************************************************ * Include the driver code * ************************************************************************ */ #include "../bdm.c" /* ************************************************************************ * Good old-fashioned UNIX driver entry points * ************************************************************************ */ static int openbsd_bdm_open (dev_t dev, int flags, int fmt, struct proc *p) { return bdm_open (MINOR (dev)); } static int openbsd_bdm_close (dev_t dev, int fflag, int devtype, struct proc *p) { return bdm_close (MINOR (dev)); } static int openbsd_bdm_read (dev_t dev, struct uio *uio, int flag) { return bdm_read (MINOR (dev), (char *)uio, uio->uio_resid); } static int openbsd_bdm_write (dev_t dev, struct uio * uio, int ioflag) { return bdm_write (MINOR (dev), (char *)uio, uio->uio_resid); } static int openbsd_bdm_ioctl (dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) { return bdm_ioctl (MINOR (dev), cmd, (unsigned long)arg); } /* * Driver entry points */ static int bdm_dev_registered = 0; void cleanup_module (void); /* * Hook driver into kernel */ static int init_module () { int minor; PRINTF ("bdm_init_module %d.%d, " __DATE__ ", " __TIME__ "\n", BDM_DRV_VERSION >> 8, BDM_DRV_VERSION & 0xff); bdm_dev_registered = 1; /* * Set up port numbers */ for (minor = 0 ; minor < (sizeof bdm_device_info / sizeof bdm_device_info[0]) ; minor++) { int port; struct BDM *self = &bdm_device_info[minor]; /* * First set the default debug level. */ self->debugFlag = BDM_DEFAULT_DEBUG; /* * Choose a port number */ switch (BDM_IFACE_MINOR (minor)) { case 0: port = 0x378; break; /* LPT1 */ case 1: port = 0x278; break; /* LPT2 */ case 2: port = 0x3bc; break; /* LPT3 */ case 3: port = 0x2bc; break; /* LPT4, ccj - made this up :-) */ default: PRINTF ("BDM driver has no address for LPT%d.\n", BDM_IFACE_MINOR (minor) + 1); cleanup_module (); return EIO; } /* * See if the port exists */ self->exists = 1; outb (0x00, port); bdm_delay (50); if (inb (port) != 0x00) { self->exists = 0; if (self->debugFlag) PRINTF ("BDM driver cannot detect LPT%d.\n", BDM_IFACE_MINOR (minor) + 1); continue; } sprintf (self->name, "bdm%d", minor); self->portBase = self->dataPort = port; self->statusPort = port + 1; self->controlPort = port + 2; self->delayTimer = 0; switch (BDM_IFACE (minor)) { case BDM_CPU32_PD: cpu32_pd_init_self (self); break; case BDM_CPU32_ICD: cpu32_icd_init_self (self); break; case BDM_COLDFIRE_PE: cf_pe_init_self (self); break; default: PRINTF ("BDM driver has no interface for minor number\n"); cleanup_module (); return EIO; } } return 0; } /* * Unhook module from kernel */ void cleanup_module (void) { int minor; for (minor = 0 ; minor < (sizeof bdm_device_info / sizeof bdm_device_info[0]) ; minor++) { struct BDM *self = &bdm_device_info[minor]; if (self->exists && self->portsAreMine) ; } if (bdm_dev_registered) { bdm_dev_registered = 0; PRINTF ("BDM driver unregistered.\n"); } } static struct cdevsw openbsd_devsw = { openbsd_bdm_open, /* open */ openbsd_bdm_close, /* close */ openbsd_bdm_read, /* read */ openbsd_bdm_write, /* write */ openbsd_bdm_ioctl, /* ioctl */ (void *)nullop, /* stop */ (void *)NULL, /* tty */ (void *)nullop, /* select */ (void *)nullop, /* mmap */ NULL /* strategy */ }; MOD_DEV("bdm", LM_DT_CHAR, BDM_MAJOR_NUMBER, &openbsd_devsw) static int bdmprobe () { /* For now, always report the BDM driver is able to drive the BDM hardware. */ return 0; } static int bdm_load(void) { int err; PRINTF("BDM init_module\n %s\n %s\n %s\n", "$RCSfile: openbsd-bdm.c,v $", "$Revision: 1.1 $", "$Date: 2004/04/18 16:51:21 $"); PRINTF(" Version %s\n Compiled at %s %s\n", "PD-interface", __DATE__, __TIME__); err = bdmprobe (); if (err) { PRINTF ("BDM driver: probe failed\n"); return err; } err = init_module(); if (err) { PRINTF ("BDM driver: load failed\n"); return err; } PRINTF ("BDM driver: loaded\n"); return 0; } static int bdm_unload(void) { PRINTF ("BDM driver: unloaded\n"); return 0; } static int bdm_handler(struct lkm_table *lkmtp, int cmd) { int iStatus = 0; struct lkm_dev *args = lkmtp->private.lkm_dev; switch ( cmd ) { case LKM_E_LOAD: iStatus = bdm_load(); break; case LKM_E_UNLOAD: iStatus = bdm_unload(); break; } return ( iStatus ); } int bdm(struct lkm_table *lkmtp, int cmd, int ver) { DISPATCH(lkmtp, cmd, ver, bdm_handler, lkm_nofunc, lkm_nofunc); }