fwmem.c revision 106810
165806Sdwmalone/*
265806Sdwmalone * Copyright (C) 2002
365806Sdwmalone * 	Hidetoshi Shimokawa. All rights reserved.
465806Sdwmalone *
565806Sdwmalone * Redistribution and use in source and binary forms, with or without
665806Sdwmalone * modification, are permitted provided that the following conditions
765806Sdwmalone * are met:
865806Sdwmalone * 1. Redistributions of source code must retain the above copyright
965806Sdwmalone *    notice, this list of conditions and the following disclaimer.
1065806Sdwmalone * 2. Redistributions in binary form must reproduce the above copyright
1165806Sdwmalone *    notice, this list of conditions and the following disclaimer in the
1265806Sdwmalone *    documentation and/or other materials provided with the distribution.
1365806Sdwmalone * 3. All advertising materials mentioning features or use of this software
1465806Sdwmalone *    must display the following acknowledgement:
1565806Sdwmalone *
1665806Sdwmalone *	This product includes software developed by Hidetoshi Shimokawa.
1765806Sdwmalone *
1865806Sdwmalone * 4. Neither the name of the author nor the names of its contributors
1965806Sdwmalone *    may be used to endorse or promote products derived from this software
2065806Sdwmalone *    without specific prior written permission.
2165806Sdwmalone *
2265806Sdwmalone * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2365806Sdwmalone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2465806Sdwmalone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2565806Sdwmalone * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2665806Sdwmalone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27175799Strhodes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2865806Sdwmalone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2965806Sdwmalone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3065806Sdwmalone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3165806Sdwmalone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3265806Sdwmalone * SUCH DAMAGE.
3365806Sdwmalone *
3465806Sdwmalone * $FreeBSD: head/sys/dev/firewire/fwmem.c 106810 2002-11-12 13:49:17Z simokawa $
3565806Sdwmalone */
3665806Sdwmalone
3765806Sdwmalone#include <sys/param.h>
3865806Sdwmalone#include <sys/systm.h>
3965806Sdwmalone#include <sys/types.h>
4065806Sdwmalone
4165806Sdwmalone#include <sys/kernel.h>
4265806Sdwmalone#include <sys/malloc.h>
4365806Sdwmalone#include <sys/conf.h>
4465806Sdwmalone#include <sys/uio.h>
4565806Sdwmalone#include <sys/sysctl.h>
4665806Sdwmalone
4765806Sdwmalone#include <sys/bus.h>
4865806Sdwmalone
4965806Sdwmalone#include <sys/signal.h>
5065806Sdwmalone#include <sys/mman.h>
5165806Sdwmalone#include <sys/ioccom.h>
5265806Sdwmalone
5365806Sdwmalone#include <dev/firewire/firewire.h>
5465806Sdwmalone#include <dev/firewire/firewirereg.h>
5565806Sdwmalone#include <dev/firewire/fwmem.h>
5665806Sdwmalone
5765806Sdwmalonestatic int fwmem_speed=2, fwmem_debug=0;
5865806Sdwmalonestatic struct fw_eui64 fwmem_eui64;
5965806SdwmaloneSYSCTL_DECL(_hw_firewire);
6065806SdwmaloneSYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
6165806Sdwmalone	"Firewire Memory Access");
6265806SdwmaloneSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
6365806Sdwmalone	&fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
6465806SdwmaloneSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_low, CTLFLAG_RW,
6565806Sdwmalone	&fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
6665806SdwmaloneSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
6765806Sdwmalone	"Fwmem link speed");
6865806SdwmaloneSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
6965806Sdwmalone	"Fwmem driver debug flag");
7065806Sdwmalone
7165806Sdwmalonestruct fw_xfer *
7265806Sdwmalonefwmem_read_quad(
7365806Sdwmalone	struct fw_device *fwdev,
7465806Sdwmalone	caddr_t	sc,
7565806Sdwmalone	u_int8_t spd,
7665806Sdwmalone	u_int16_t dst_hi,
7765806Sdwmalone	u_int32_t dst_lo,
7865806Sdwmalone	void (*hand)(struct fw_xfer *))
7965806Sdwmalone{
8065806Sdwmalone	struct fw_xfer *xfer;
8165806Sdwmalone	struct fw_pkt *fp;
8265806Sdwmalone
8365806Sdwmalone	xfer = fw_xfer_alloc();
8465806Sdwmalone	if (xfer == NULL)
8565806Sdwmalone		return NULL;
8679755Sdd
87197330Sed	xfer->fc = fwdev->fc;
8865806Sdwmalone	xfer->dst = FWLOCALBUS | fwdev->dst;
8965806Sdwmalone	xfer->spd = spd;
9065806Sdwmalone	xfer->send.len = 12;
9165806Sdwmalone	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
9265806Sdwmalone
9365806Sdwmalone	if (xfer->send.buf == NULL)
9465806Sdwmalone		goto error;
95197330Sed
9665806Sdwmalone	xfer->send.off = 0;
9765806Sdwmalone	xfer->act.hand = hand;
9865806Sdwmalone	xfer->retry_req = fw_asybusy;
9965806Sdwmalone	xfer->sc = NULL;
10065806Sdwmalone
10165806Sdwmalone	fp = (struct fw_pkt *)xfer->send.buf;
10265806Sdwmalone	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
10365806Sdwmalone	fp->mode.rreqq.dst = htons(xfer->dst);
10465806Sdwmalone	fp->mode.rreqq.dest_hi = htons(dst_hi);
10565806Sdwmalone	fp->mode.rreqq.dest_lo = htonl(dst_lo);
10665806Sdwmalone
10765806Sdwmalone	if (fwmem_debug)
10865806Sdwmalone		printf("fwmem: %d %04x:%08x\n", fwdev->dst, dst_hi, dst_lo);
10965806Sdwmalone
11065806Sdwmalone	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
11165806Sdwmalone		return xfer;
11265806Sdwmalone
11365806Sdwmaloneerror:
11465806Sdwmalone	fw_xfer_free(xfer);
11565806Sdwmalone	return NULL;
11665806Sdwmalone}
11765806Sdwmalone
11865806Sdwmalonestruct fw_xfer *
11965806Sdwmalonefwmem_write_quad(
12065806Sdwmalone	struct fw_device *fwdev,
12165806Sdwmalone	caddr_t	sc,
12265806Sdwmalone	u_int8_t spd,
12365806Sdwmalone	u_int16_t dst_hi,
12465806Sdwmalone	u_int32_t dst_lo,
12565806Sdwmalone	u_int32_t data,
12665806Sdwmalone	void (*hand)(struct fw_xfer *))
12765806Sdwmalone{
12865806Sdwmalone	struct fw_xfer *xfer;
12965806Sdwmalone	struct fw_pkt *fp;
13065806Sdwmalone
13165806Sdwmalone	xfer = fw_xfer_alloc();
13265806Sdwmalone	if (xfer == NULL)
13365806Sdwmalone		return NULL;
13465806Sdwmalone
13565806Sdwmalone	xfer->fc = fwdev->fc;
13665806Sdwmalone	xfer->dst = FWLOCALBUS | fwdev->dst;
13765806Sdwmalone	xfer->spd = spd;
13865806Sdwmalone	xfer->send.len = 16;
13965806Sdwmalone	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
14065806Sdwmalone
14165806Sdwmalone	if (xfer->send.buf == NULL)
14265806Sdwmalone		goto error;
14365806Sdwmalone
14465806Sdwmalone	xfer->send.off = 0;
14565806Sdwmalone	xfer->act.hand = hand;
14665806Sdwmalone	xfer->retry_req = fw_asybusy;
14765806Sdwmalone	xfer->sc = sc;
14865806Sdwmalone
14965806Sdwmalone	fp = (struct fw_pkt *)xfer->send.buf;
15065806Sdwmalone	fp->mode.wreqq.tcode = FWTCODE_RREQQ;
15165806Sdwmalone	fp->mode.wreqq.dst = htons(xfer->dst);
15265806Sdwmalone	fp->mode.wreqq.dest_hi = htons(dst_hi);
15365806Sdwmalone	fp->mode.wreqq.dest_lo = htonl(dst_lo);
15465806Sdwmalone
15565806Sdwmalone	fp->mode.wreqq.data = htonl(data);
15665806Sdwmalone
15765806Sdwmalone	if (fwmem_debug)
15865806Sdwmalone		printf("fwmem: %d %04x:%08x\n", fwdev->dst, dst_hi, dst_lo);
15965806Sdwmalone
16065806Sdwmalone	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
16165806Sdwmalone		return xfer;
16265806Sdwmalone
16365806Sdwmaloneerror:
16465806Sdwmalone	fw_xfer_free(xfer);
16565806Sdwmalone	return NULL;
16665806Sdwmalone}
16765806Sdwmalone
168175799Strhodesstruct fw_xfer *
169175799Strhodesfwmem_read_block(
170175799Strhodes	struct fw_device *fwdev,
171175799Strhodes	caddr_t	sc,
172175799Strhodes	u_int8_t spd,
173175799Strhodes	u_int16_t dst_hi,
174175799Strhodes	u_int32_t dst_lo,
175175799Strhodes	int len,
176175799Strhodes	void (*hand)(struct fw_xfer *))
17779755Sdd{
17865806Sdwmalone	struct fw_xfer *xfer;
17979755Sdd	struct fw_pkt *fp;
18065806Sdwmalone
18179755Sdd	xfer = fw_xfer_alloc();
18265806Sdwmalone	if (xfer == NULL)
18379755Sdd		return NULL;
18465806Sdwmalone
18579755Sdd	xfer->fc = fwdev->fc;
18665806Sdwmalone	xfer->dst = FWLOCALBUS | fwdev->dst;
18779755Sdd	xfer->spd = spd;
18865806Sdwmalone	xfer->send.len = 16;
18979755Sdd	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
19065806Sdwmalone
19179755Sdd	if (xfer->send.buf == NULL)
19265806Sdwmalone		goto error;
19379755Sdd
19465806Sdwmalone	xfer->send.off = 0;
19579755Sdd	xfer->act.hand = fw_asy_callback;
19665806Sdwmalone	xfer->retry_req = fw_asybusy;
19779755Sdd	xfer->sc = NULL;
19865806Sdwmalone
19979755Sdd	fp = (struct fw_pkt *)xfer->send.buf;
20065806Sdwmalone	fp->mode.rreqb.tcode = FWTCODE_RREQB;
20179755Sdd	fp->mode.rreqb.dst = htons(xfer->dst);
20265806Sdwmalone	fp->mode.rreqb.dest_hi = htons(dst_hi);
20379755Sdd	fp->mode.rreqb.dest_lo = htonl(dst_lo);
20465806Sdwmalone	fp->mode.rreqb.len = htons(len);
20579755Sdd
20665806Sdwmalone	if (fwmem_debug)
20779755Sdd		printf("fwmem: %d %04x:%08x %d\n", fwdev->dst,
20865806Sdwmalone				dst_hi, dst_lo, len);
20979755Sdd	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
21065806Sdwmalone		return xfer;
21179755Sdd
21265806Sdwmaloneerror:
21379755Sdd	fw_xfer_free(xfer);
21465806Sdwmalone	return NULL;
21579755Sdd}
21665806Sdwmalone
21779755Sddint
21865806Sdwmalonefwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
21965806Sdwmalone{
22065806Sdwmalone	int err = 0;
22165806Sdwmalone	return err;
22265806Sdwmalone}
22365806Sdwmalone
22465806Sdwmaloneint
22579755Sddfwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
22665806Sdwmalone{
22779755Sdd	int err = 0;
22865806Sdwmalone	return err;
22979755Sdd}
23065806Sdwmalone
23165806Sdwmalone#define MAXLEN 2048
23279755Sdd#define USE_QUAD 0
23365806Sdwmaloneint
23479755Sddfwmem_read (dev_t dev, struct uio *uio, int ioflag)
23565806Sdwmalone{
23679755Sdd	struct firewire_softc *sc;
23765806Sdwmalone	struct fw_device *fwdev;
23865806Sdwmalone	struct fw_xfer *xfer;
23979755Sdd	int err = 0, pad;
240134117Ssimon        int unit = DEV2UNIT(dev);
241134117Ssimon	u_int16_t dst_hi;
242132993Sscottl	u_int32_t dst_lo;
243132993Sscottl	off_t offset;
244132993Sscottl	int len;
245132993Sscottl
24674145Sache	sc = devclass_get_softc(firewire_devclass, unit);
24774145Sache	fwdev = fw_noderesolve(sc->fc, fwmem_eui64);
24865806Sdwmalone	if (fwdev == NULL) {
24965806Sdwmalone		printf("fwmem: no such device ID:%08x%08x\n",
25065806Sdwmalone			fwmem_eui64.hi, fwmem_eui64.lo);
25165806Sdwmalone		return EINVAL;
25265806Sdwmalone	}
25365806Sdwmalone
25465806Sdwmalone	pad = uio->uio_offset % 4;
25565806Sdwmalone	if  (fwmem_debug && pad != 0)
25665806Sdwmalone		printf("unaligned\n");
25765806Sdwmalone	while(uio->uio_resid > 0) {
25865806Sdwmalone		offset = uio->uio_offset;
25965806Sdwmalone		offset -= pad;
26065806Sdwmalone		dst_hi = (offset >> 32) & 0xffff;
26165806Sdwmalone		dst_lo = offset & 0xffffffff;
26265806Sdwmalone#if USE_QUAD
26365806Sdwmalone		xfer = fwmem_read_quad(fwdev, NULL, fwmem_speed,
26465806Sdwmalone				dst_hi, dst_lo, fw_asy_callback);
26565806Sdwmalone		if (xfer == NULL)
26665806Sdwmalone			return EINVAL;
26765806Sdwmalone		err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
26865806Sdwmalone		if (err !=0 || xfer->resp != 0 || xfer->recv.buf == NULL)
26965806Sdwmalone			return EINVAL; /* XXX */
27065806Sdwmalone		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*3 + pad,
27165806Sdwmalone			4 - pad, uio);
27265806Sdwmalone#else
27365806Sdwmalone		len = uio->uio_resid;
27465806Sdwmalone		if (len > MAXLEN)
27565806Sdwmalone			len = MAXLEN;
27665806Sdwmalone		xfer = fwmem_read_block(fwdev, NULL, fwmem_speed,
277197330Sed				dst_hi, dst_lo, len, fw_asy_callback);
27865806Sdwmalone		if (xfer == NULL)
27965806Sdwmalone			return EINVAL;
28065806Sdwmalone		err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
28165806Sdwmalone		if (err != 0 || xfer->resp != 0 || xfer->recv.buf == NULL)
28265806Sdwmalone			return EINVAL; /* XXX */
28365806Sdwmalone		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*4 + pad,
28465806Sdwmalone			len - pad, uio);
28565806Sdwmalone#endif
28665806Sdwmalone		if (err)
28765806Sdwmalone			return err;
28865806Sdwmalone		fw_xfer_free(xfer);
28965806Sdwmalone		pad = 0;
29065806Sdwmalone	}
29165806Sdwmalone	return err;
29265806Sdwmalone}
293197330Sedint
29465806Sdwmalonefwmem_write (dev_t dev, struct uio *uio, int ioflag)
29565806Sdwmalone{
29665806Sdwmalone	return EINVAL;
29765806Sdwmalone}
29868965Sruint
29965806Sdwmalonefwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
30065806Sdwmalone{
30165806Sdwmalone	return EINVAL;
30265806Sdwmalone}
30365806Sdwmaloneint
30465806Sdwmalonefwmem_poll (dev_t dev, int events, fw_proc *td)
30565806Sdwmalone{
30665806Sdwmalone	return EINVAL;
30765806Sdwmalone}
30865806Sdwmaloneint
30965806Sdwmalonefwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
31065806Sdwmalone{
31165806Sdwmalone	return EINVAL;
31265806Sdwmalone}
31365806Sdwmalone