715 lines
20 KiB
C
715 lines
20 KiB
C
/**************************************************************************
|
|
* *
|
|
* Copyright (C) 1990-1993, Silicon Graphics, Inc *
|
|
* *
|
|
* These coded instructions, statements, and computer programs contain *
|
|
* unpublished proprietary information of Silicon Graphics, Inc., and *
|
|
* are protected by Federal copyright law. They may not be disclosed *
|
|
* to third parties or copied or duplicated in any form, in whole or *
|
|
* in part, without the prior written consent of Silicon Graphics, Inc. *
|
|
* *
|
|
**************************************************************************/
|
|
|
|
#ident "io/sample_xtalk.c: $Revision: 1.14 $"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/cpu.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/cmn_err.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/cred.h>
|
|
#include <ksys/ddmap.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/invent.h>
|
|
#include <sys/debug.h>
|
|
#include <sys/sbd.h>
|
|
#include <sys/kmem.h>
|
|
#include <sys/edt.h>
|
|
#include <sys/dmamap.h>
|
|
#include <sys/hwgraph.h>
|
|
#include <sys/iobus.h>
|
|
#include <sys/iograph.h>
|
|
#include <sys/param.h>
|
|
#include <sys/pio.h>
|
|
#include <sys/sema.h>
|
|
#include <sys/ddi.h>
|
|
|
|
#include <sys/xtalk/xwidget.h>
|
|
|
|
#define NEW(ptr) (ptr = kmem_alloc(sizeof (*(ptr)), KM_SLEEP))
|
|
#define DEL(ptr) (kmem_free(ptr, sizeof (*(ptr))))
|
|
|
|
/*
|
|
* xsamp: a generic device driver for a generic crosstalk device.
|
|
*/
|
|
|
|
int xsamp_devflag = D_MP;
|
|
|
|
|
|
/* =====================================================================
|
|
* Device-Related Constants and Structures
|
|
*/
|
|
|
|
#define XSAMP_WIDGET_PART_NUM 0x5555
|
|
#define XSAMP_WIDGET_MFGR_NUM 0x555
|
|
|
|
/*
|
|
* All registers on the Sample XTalk Client
|
|
* device are 64 bits wide.
|
|
*/
|
|
typedef __uint64_t xsamp_reg_t;
|
|
|
|
typedef volatile struct xsamp_regs_s *xsamp_regs_t; /* device registers */
|
|
typedef struct xsamp_soft_s *xsamp_soft_t; /* software state */
|
|
|
|
/*
|
|
* xsamp_regs: layout of device registers
|
|
*
|
|
* As usual for crosstalk devices, offset zero
|
|
* starts with standard widget registers.
|
|
*
|
|
* The xsamp device has chosen to place its
|
|
* device registers at offset 0x1000 in its
|
|
* crosstalk address space.
|
|
*/
|
|
|
|
#define XSAMP_REGS_OFFSET 0x1000
|
|
|
|
struct xsamp_regs_s {
|
|
xsamp_reg_t xr_control;
|
|
xsamp_reg_t xr_status;
|
|
|
|
xsamp_reg_t xr_dma_ahi;
|
|
xsamp_reg_t xr_dma_vec;
|
|
};
|
|
|
|
struct xsamp_soft_s {
|
|
vertex_hdl_t xs_conn; /* xtalk connection */
|
|
vertex_hdl_t xs_vhdl; /* backpointer to device vertex */
|
|
vertex_hdl_t xs_blockv; /* backpointer to block vertex */
|
|
vertex_hdl_t xs_charv; /* backpointer to char vertex */
|
|
widget_cfg_t *xs_cfg; /* cached ptr to my config regs */
|
|
xsamp_regs_t xs_regs; /* cached ptr to my regs */
|
|
|
|
unsigned xs_sst; /* soft status */
|
|
|
|
#define XSAMP_SST_RX_READY (0x0001)
|
|
#define XSAMP_SST_TX_READY (0x0002)
|
|
#define XSAMP_SST_ERROR (0x0004)
|
|
|
|
xtalk_intr_t xs_err_intr; /* xtalk intr for widget errors */
|
|
xtalk_intr_t xs_dma_intr; /* xtalk intr for dma interrupt */
|
|
|
|
xtalk_dmamap_t xs_ctl_dmamap; /* control channel dma mapping resoures */
|
|
xtalk_dmamap_t xs_str_dmamap; /* stream channel dma mapping resoures */
|
|
|
|
struct pollhead *xs_pollhead; /* for poll() */
|
|
|
|
int xs_blocks; /* block device size in NBPSCTR blocks */
|
|
};
|
|
|
|
#define xsamp_soft_set(v,i) device_info_set((v),(void *)(i))
|
|
#define xsamp_soft_get(v) ((xsamp_soft_t)device_info_get((v)))
|
|
|
|
|
|
/* =====================================================================
|
|
* Function Table of Contents
|
|
*/
|
|
|
|
extern void xsamp_init(void);
|
|
extern int xsamp_reg(void);
|
|
extern int xsamp_unreg(void);
|
|
extern int xsamp_attach(vertex_hdl_t conn);
|
|
|
|
extern int xsamp_open(dev_t * devp, int oflag, int otyp, cred_t * crp);
|
|
extern int xsamp_close(dev_t dev, int oflag, int otyp, cred_t * crp);
|
|
|
|
extern int xsamp_ioctl(dev_t dev, int cmd, void *arg,
|
|
int mode, cred_t * crp, int *rvalp);
|
|
|
|
extern int xsamp_read(dev_t dev, uio_t * uiop, cred_t * crp);
|
|
extern int xsamp_write(dev_t dev, uio_t * uiop, cred_t * crp);
|
|
|
|
extern int xsamp_strategy(struct buf *bp);
|
|
|
|
extern int xsamp_poll(dev_t dev, short events, int anyyet,
|
|
short *reventsp, struct pollhead **phpp,
|
|
unsigned int *genp);
|
|
|
|
extern int xsamp_map(dev_t dev, vhandl_t * vt,
|
|
off_t off, size_t len, uint_t prot);
|
|
extern int xsamp_unmap(dev_t dev, vhandl_t * vt);
|
|
|
|
static void xsamp_err_intr(intr_arg_t arg);
|
|
static void xsamp_dma_intr(intr_arg_t arg);
|
|
static int xsamp_err_setfunc(xtalk_intr_t intr);
|
|
static int xsamp_dma_setfunc(xtalk_intr_t intr);
|
|
|
|
extern int xsamp_unload(void);
|
|
extern void xsamp_halt(void);
|
|
extern int xsamp_size(dev_t dev);
|
|
extern int xsamp_print(dev_t, char *str);
|
|
|
|
/* =====================================================================
|
|
* Driver Initialization
|
|
*/
|
|
|
|
/*
|
|
* xsamp_init: called once during system startup or
|
|
* when a loadable driver is loaded.
|
|
*/
|
|
void
|
|
xsamp_init(void)
|
|
{
|
|
printf("xsamp_init()\n");
|
|
}
|
|
|
|
/*
|
|
* xsamp_reg: called once during system startup or
|
|
* when a loadable driver is loaded.
|
|
*
|
|
* NOTE: a bus provider register routine should always be
|
|
* called from _reg, rather than from _init. In the case
|
|
* of a loadable module, the devsw is not hooked up
|
|
* when the _init routines are called.
|
|
*
|
|
*/
|
|
int
|
|
xsamp_reg(void)
|
|
{
|
|
printf("xsamp_reg()\n");
|
|
|
|
xwidget_driver_register(XSAMP_WIDGET_PART_NUM,
|
|
XSAMP_WIDGET_MFGR_NUM,
|
|
"xsamp_",
|
|
0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* xsamp_unreg: called when a loadable driver is unloaded.
|
|
*/
|
|
int
|
|
xsamp_unreg(void)
|
|
{
|
|
xwidget_driver_unregister("xsamp_");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* xsamp_attach: called by the xtalk infrastructure
|
|
* once for each vertex representing a crosstalk
|
|
* widget.
|
|
*
|
|
* In large configurations, it is possible for a
|
|
* huge number of CPUs to enter this routine all at
|
|
* nearly the same time, for different specific
|
|
* instances of the device. Attempting to give your
|
|
* devices sequence numbers based on the order they
|
|
* are found in the system is not only futile but
|
|
* may be dangerous as the order may differ from
|
|
* run to run.
|
|
*/
|
|
int
|
|
xsamp_attach(vertex_hdl_t conn)
|
|
{
|
|
vertex_hdl_t vhdl, blockv, charv;
|
|
widget_cfg_t *cfg;
|
|
xsamp_regs_t regs;
|
|
xsamp_soft_t soft;
|
|
|
|
printf("xsamp_attach()\n");
|
|
|
|
hwgraph_device_add(conn, "xsamp", "xsamp_", &vhdl, &blockv, &charv);
|
|
|
|
/*
|
|
* Allocate a place to put per-device
|
|
* information for this vertex. Then
|
|
* associate it with the vertex in the
|
|
* most efficient manner.
|
|
*/
|
|
NEW(soft);
|
|
ASSERT(soft != NULL);
|
|
xsamp_soft_set(vhdl, soft);
|
|
xsamp_soft_set(blockv, soft);
|
|
xsamp_soft_set(charv, soft);
|
|
|
|
soft->xs_conn = conn;
|
|
soft->xs_vhdl = vhdl;
|
|
soft->xs_blockv = blockv;
|
|
soft->xs_charv = charv;
|
|
|
|
|
|
/*
|
|
* Find our WIDGET CONFIG registers.
|
|
* The "widget_cfg_t" structure defined in
|
|
* <sys/xtalk/xwidget.h> maps accurately to the
|
|
* standard registers expected to be found
|
|
* starting at the base of the widget's address
|
|
* space, for all crosstalk widgets.
|
|
*/
|
|
|
|
cfg = (widget_cfg_t *) xtalk_piotrans_addr
|
|
(conn, 0, /* device and (override) dev_info */
|
|
0, sizeof(*cfg), /* xtalk base and size */
|
|
0); /* flag word */
|
|
|
|
soft->xs_cfg = cfg; /* save for later */
|
|
|
|
printf("xsamp_attach: I can see my cfg regs at 0x%x\n", cfg);
|
|
|
|
/*
|
|
* Get a pointer to our DEVICE registers
|
|
*/
|
|
|
|
regs = (xsamp_regs_t) xtalk_piotrans_addr
|
|
(conn, 0, /* device and (override) dev_info */
|
|
XSAMP_REGS_OFFSET, sizeof(*regs), /* xtalk base and size */
|
|
0); /* flag word */
|
|
|
|
soft->xs_regs = regs; /* save for later */
|
|
|
|
printf("xsamp_attach: I can see my device regs at 0x%x\n", regs);
|
|
|
|
/*
|
|
* Set up our "widget error" interrupt.
|
|
* Note the manipulation of dev_desc to get
|
|
* proper priority for the error; we may shift
|
|
* to passing this information as a flag to
|
|
* xtlk_inter_alloc. Send feedback on this issue to
|
|
* limes@sgi.com and len@sgi.com if this matters
|
|
* a great deal to you (but we promise that this
|
|
* code will keep working ...)
|
|
*/
|
|
|
|
{
|
|
device_desc_t error_intr_desc;
|
|
|
|
error_intr_desc = device_desc_dup(vhdl);
|
|
device_desc_flags_set(error_intr_desc,
|
|
device_desc_flags_get(error_intr_desc) |
|
|
D_INTR_ISERR);
|
|
|
|
soft->xs_err_intr = xtalk_intr_alloc(conn, error_intr_desc, vhdl);
|
|
xtalk_intr_connect(soft->xs_err_intr,
|
|
xsamp_err_intr, soft,
|
|
xsamp_err_setfunc, soft,
|
|
(void *) 0);
|
|
|
|
device_desc_free(error_intr_desc);
|
|
}
|
|
|
|
/*
|
|
* Set up our "dma complete" interrupt.
|
|
* No overrides, so we pass "0" for dev_desc.
|
|
* This is the normal way to set up interrupts.
|
|
*/
|
|
|
|
soft->xs_dma_intr = xtalk_intr_alloc(conn, 0, vhdl);
|
|
xtalk_intr_connect(soft->xs_dma_intr,
|
|
xsamp_dma_intr, soft,
|
|
xsamp_dma_setfunc, soft,
|
|
(void *) 0);
|
|
|
|
/*
|
|
* For xtalk clients, *now* is the time to
|
|
* allocate pollhead structures.
|
|
*/
|
|
soft->xs_pollhead = phalloc(0);
|
|
|
|
return 0; /* attach successful */
|
|
}
|
|
|
|
/* =====================================================================
|
|
* DRIVER OPEN/CLOSE
|
|
*/
|
|
|
|
/*
|
|
* xsamp_open: called when a device special file is
|
|
* opened or when a block device is mounted.
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
xsamp_open(dev_t * devp, int oflag, int otyp, cred_t * crp)
|
|
{
|
|
vertex_hdl_t vhdl = dev_to_vhdl(*devp);
|
|
xsamp_soft_t soft = xsamp_soft_get(vhdl);
|
|
xsamp_regs_t regs = soft->xs_regs;
|
|
|
|
printf("xsamp_open() regs=%x\n", regs);
|
|
|
|
/*
|
|
* BLOCK DEVICES: now would be a good time to
|
|
* calculate the size of the device and stash it
|
|
* away for use by xsamp_size.
|
|
*/
|
|
|
|
/*
|
|
* USER ABI (64-bit): chances are, you are being
|
|
* compiled for use in a 64-bit IRIX kernel; if
|
|
* you use the _ioctl or _poll entry points, now
|
|
* would be a good time to test and save the
|
|
* user process' model so you know how to
|
|
* interpret the user ioctl and poll requests.
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* xsamp_close: called when a device special file
|
|
* is closed by a process and no other processes
|
|
* still have it open ("last close").
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
xsamp_close(dev_t dev, int oflag, int otyp, cred_t * crp)
|
|
{
|
|
vertex_hdl_t vhdl = dev_to_vhdl(dev);
|
|
xsamp_soft_t soft = xsamp_soft_get(vhdl);
|
|
xsamp_regs_t regs = soft->xs_regs;
|
|
|
|
printf("xsamp_close() regs=%x\n", regs);
|
|
return 0;
|
|
}
|
|
|
|
/* =====================================================================
|
|
* CONTROL ENTRY POINT
|
|
*/
|
|
|
|
/*
|
|
* xsamp_ioctl: a user has made an ioctl request
|
|
* for an open character device.
|
|
*
|
|
* cmd and arg are as specified by the user; arg is
|
|
* probably a pointer to something in the user's
|
|
* address space, so you need to use copyin() to
|
|
* read through it and copyout() to write through it.
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
xsamp_ioctl(dev_t dev, int cmd, void *arg,
|
|
int mode, cred_t * crp, int *rvalp)
|
|
{
|
|
vertex_hdl_t vhdl = dev_to_vhdl(dev);
|
|
xsamp_soft_t soft = xsamp_soft_get(vhdl);
|
|
xsamp_regs_t regs = soft->xs_regs;
|
|
|
|
printf("xsamp_ioctl() regs=%x\n", regs);
|
|
|
|
*rvalp = -1;
|
|
return ENOTTY; /* TeleType® is a registered trademark. */
|
|
}
|
|
|
|
/* =====================================================================
|
|
* DATA TRANSFER ENTRY POINTS
|
|
*
|
|
* Since I'm trying to provide an example for both
|
|
* character and block devices, I'm routing read
|
|
* and write back through strategy as described in
|
|
* the IRIX Device Driver Programming Guide.
|
|
*
|
|
* This limits our character driver to reading and
|
|
* writing in multiples of the standard sector
|
|
* length.
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
xsamp_read(dev_t dev, uio_t * uiop, cred_t * crp)
|
|
{
|
|
return physiock(xsamp_strategy,
|
|
0, /* alocate temp buffer & buf_t */
|
|
dev, /* dev_t arg for strategy */
|
|
B_READ, /* direction flag for buf_t */
|
|
xsamp_size(dev),
|
|
uiop);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
xsamp_write(dev_t dev, uio_t * uiop, cred_t * crp)
|
|
{
|
|
return physiock(xsamp_strategy,
|
|
0, /* alocate temp buffer & buf_t */
|
|
dev, /* dev_t arg for strategy */
|
|
B_WRITE, /* direction flag for buf_t */
|
|
xsamp_size(dev),
|
|
uiop);
|
|
}
|
|
|
|
/* ARGSUSED1 */
|
|
int
|
|
xsamp_strategy(struct buf *bp)
|
|
{
|
|
/*
|
|
* I think Len has some code that I can
|
|
* drop into here.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
/* =====================================================================
|
|
* POLL ENTRY POINT
|
|
*/
|
|
|
|
int
|
|
xsamp_poll(dev_t dev, short events, int anyyet,
|
|
short *reventsp, struct pollhead **phpp, unsigned int *genp)
|
|
{
|
|
vertex_hdl_t vhdl = dev_to_vhdl(dev);
|
|
xsamp_soft_t soft = xsamp_soft_get(vhdl);
|
|
xsamp_regs_t regs = soft->xs_regs;
|
|
|
|
short happened = 0;
|
|
unsigned int gen;
|
|
|
|
printf("xsamp_poll() regs=%x\n", regs);
|
|
|
|
/*
|
|
* Need to snapshot the pollhead generation number before we check the
|
|
* device state. In many drivers a lock is used to interlock the
|
|
* ``high'' and ``low'' portions of the driver. In those cases we
|
|
* can wait to do this snapshot till we're in the critical region.
|
|
* Sanpshotting it early isn't a problem since that merely makes the
|
|
* snapshotted generation number a more conservative estimate of
|
|
* what ``generation'' of the pollhead our event state report indicates.
|
|
*/
|
|
gen = POLLGEN(soft->xs_pollhead);
|
|
|
|
if (events & (POLLIN | POLLRDNORM))
|
|
if (soft->xs_sst & XSAMP_SST_RX_READY)
|
|
happened |= POLLIN | POLLRDNORM;
|
|
|
|
if (events & POLLOUT)
|
|
if (soft->xs_sst & XSAMP_SST_TX_READY)
|
|
happened |= POLLOUT;
|
|
|
|
if (soft->xs_sst & XSAMP_SST_ERROR)
|
|
happened |= POLLERR;
|
|
|
|
*reventsp = happened;
|
|
|
|
if (!happened && anyyet) {
|
|
*phpp = soft->xs_pollhead;
|
|
*genp = gen;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* =====================================================================
|
|
* MEMORY MAP ENTRY POINTS
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
xsamp_map(dev_t dev, vhandl_t * vt,
|
|
off_t off, size_t len, uint_t prot)
|
|
{
|
|
vertex_hdl_t vhdl = dev_to_vhdl(dev);
|
|
xsamp_soft_t soft = xsamp_soft_get(vhdl);
|
|
vertex_hdl_t conn = soft->xs_conn;
|
|
xsamp_regs_t regs = soft->xs_regs;
|
|
caddr_t kaddr;
|
|
|
|
printf("xsamp_map() regs=%x\n", regs);
|
|
|
|
/*
|
|
* We're gonna allow anyone to mmap our
|
|
* entire widget address space, if they want.
|
|
*/
|
|
|
|
kaddr = (caddr_t) xtalk_piotrans_addr(conn, 0, off, len, 0);
|
|
if (kaddr == NULL)
|
|
return EINVAL;
|
|
|
|
len = ctob(btoc(len)); /* make len page aligned */
|
|
|
|
v_mapphys(vt, kaddr, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ARGSUSED2 */
|
|
int
|
|
xsamp_unmap(dev_t dev, vhandl_t * vt)
|
|
{
|
|
/*
|
|
* If you had to do an xtalk_piomap_alloc inside
|
|
* xsamp_map, this is the place to chase down
|
|
* the xtalk_piomap_t for xtalk_piomap_free.
|
|
*/
|
|
return (0);
|
|
}
|
|
|
|
/* =====================================================================
|
|
* INTERRUPT ENTRY POINTS
|
|
*
|
|
* IRIX will look for (and not find) xsamp_intr;
|
|
* generally, the interrupt requirements for
|
|
* crosstalk widgets are more complex (besides,
|
|
* someone needs to set up the hardware).
|
|
*
|
|
* xtalk infrastructure clients explicitly notify
|
|
* the infrastructure of their interrupt needs as
|
|
* each device instance is attached.
|
|
*/
|
|
|
|
static void
|
|
xsamp_err_intr(intr_arg_t arg)
|
|
{
|
|
xsamp_soft_t soft = (xsamp_soft_t) arg;
|
|
vertex_hdl_t vhdl = soft->xs_vhdl;
|
|
xsamp_regs_t regs = soft->xs_regs;
|
|
|
|
cmn_err(CE_WARN, "%v error intr; regs at 0x%x\n", vhdl, regs);
|
|
}
|
|
|
|
static void
|
|
xsamp_dma_intr(intr_arg_t arg)
|
|
{
|
|
xsamp_soft_t soft = (xsamp_soft_t) arg;
|
|
vertex_hdl_t vhdl = soft->xs_vhdl;
|
|
xsamp_regs_t regs = soft->xs_regs;
|
|
|
|
cmn_err(CE_WARN, "%v dma done; regs at 0x%x\n", vhdl, regs);
|
|
|
|
/*
|
|
* for each buf our hardware has processed,
|
|
* set buf->b_resid,
|
|
* call xtalk_dmamap_done,
|
|
* call bioerror() or biodone().
|
|
*
|
|
* XXX- would it be better for buf->b_iodone
|
|
* to be used to get to xtalk_dmamap_done?
|
|
*/
|
|
|
|
/*
|
|
* may want to call pollwakeup.
|
|
*/
|
|
}
|
|
|
|
/* =====================================================================
|
|
* INTERRUPT DESTINATION SELECTION
|
|
*
|
|
* It may be necessary to migrate xtalk widget
|
|
* interrupts around the system; without
|
|
* provocation from the driver, the infrastructure
|
|
* could call our setfunc entry points, presented
|
|
* to it at attach time.
|
|
*/
|
|
|
|
/* =====================================================================
|
|
* Interrupt Management
|
|
*/
|
|
|
|
static int
|
|
xsamp_err_setfunc(xtalk_intr_t intr)
|
|
{
|
|
xwidgetnum_t targ = xtalk_intr_target_get(intr);
|
|
iopaddr_t addr = xtalk_intr_addr_get(intr);
|
|
xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr);
|
|
xsamp_soft_t soft = (xsamp_soft_t) xtalk_intr_sfarg_get(intr);
|
|
widget_cfg_t *cfg = soft->xs_cfg;
|
|
|
|
cfg->w_intdest_upper_addr =
|
|
((0xFF000000 & (vect << 24)) |
|
|
(0x000F0000 & (targ << 16)) |
|
|
(0x0000FFFF & (addr >> 32)));
|
|
cfg->w_intdest_lower_addr = 0xFFFFFFFF & addr;
|
|
|
|
printf("xsamp: error ints now going to widget 0x%X, offset 0x%X, vector 0x%X\n",
|
|
targ, addr, vect);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
xsamp_dma_setfunc(xtalk_intr_t intr)
|
|
{
|
|
xwidgetnum_t targ = xtalk_intr_target_get(intr);
|
|
iopaddr_t addr = xtalk_intr_addr_get(intr);
|
|
xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr);
|
|
xsamp_soft_t soft = (xsamp_soft_t) xtalk_intr_sfarg_get(intr);
|
|
xsamp_regs_t regs = soft->xs_regs;
|
|
|
|
/*
|
|
* The xsamp device sends DMADONE interrupts to the same
|
|
* target as ERROR interrupts, and to mostly the same
|
|
* address, but uses a different vector and allows
|
|
* some address bits to be different.
|
|
*
|
|
* We should probably ASSERT that the xtalk widget
|
|
* target number and the low 32 bits of the address
|
|
* match.
|
|
*/
|
|
regs->xr_dma_vec = vect;
|
|
regs->xr_dma_ahi = 0x0000FFFF & (addr >> 32);
|
|
|
|
printf("xsamp: dma done ints now going to widget 0x%X, offset 0x%X, vector 0x%X\n",
|
|
targ, addr, vect);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* =====================================================================
|
|
* SUPPORT ENTRY POINTS
|
|
*/
|
|
|
|
/*
|
|
* xsamp_unload: tear down EVERYTHING so the driver
|
|
* can be unloaded. Return nonzero if you can't.
|
|
*/
|
|
|
|
int
|
|
xsamp_unload(void)
|
|
{
|
|
/*
|
|
* I'm not sure I *can* ... yet.
|
|
*/
|
|
return -1; /* zero would be "ok, did it." */
|
|
}
|
|
|
|
/*
|
|
* xsamp_halt: called during orderly system
|
|
* shutdown; no other device driver call will be
|
|
* made after this one.
|
|
*/
|
|
|
|
void
|
|
xsamp_halt(void)
|
|
{
|
|
printf("xsamp_halt()\n");
|
|
}
|
|
|
|
/*
|
|
* xsamp_size: return the size of the device in
|
|
* "sector" units (multiples of NBPSCTR).
|
|
*/
|
|
int
|
|
xsamp_size(dev_t dev)
|
|
{
|
|
vertex_hdl_t vhdl = dev_to_vhdl(dev);
|
|
xsamp_soft_t soft = xsamp_soft_get(vhdl);
|
|
|
|
return soft->xs_blocks;
|
|
}
|
|
|
|
/*
|
|
* xsamp_print: used by the kernel to report an
|
|
* error detected on a block device.
|
|
*/
|
|
int
|
|
xsamp_print(dev_t dev, char *str)
|
|
{
|
|
cmn_err(CE_NOTE, "%V: %s\n", dev, str);
|
|
return 0;
|
|
}
|