fwmem.c revision 103285
1130407Sdfr/*
2130407Sdfr * Copyright (C) 2002
3130407Sdfr * 	Hidetoshi Shimokawa. All rights reserved.
4130407Sdfr *
5130407Sdfr * Redistribution and use in source and binary forms, with or without
6130407Sdfr * modification, are permitted provided that the following conditions
7130407Sdfr * are met:
8130407Sdfr * 1. Redistributions of source code must retain the above copyright
9130407Sdfr *    notice, this list of conditions and the following disclaimer.
10130407Sdfr * 2. Redistributions in binary form must reproduce the above copyright
11130407Sdfr *    notice, this list of conditions and the following disclaimer in the
12130407Sdfr *    documentation and/or other materials provided with the distribution.
13130407Sdfr * 3. All advertising materials mentioning features or use of this software
14130407Sdfr *    must display the following acknowledgement:
15130407Sdfr *
16130407Sdfr *	This product includes software developed by Hidetoshi Shimokawa.
17130407Sdfr *
18130407Sdfr * 4. Neither the name of the author nor the names of its contributors
19130407Sdfr *    may be used to endorse or promote products derived from this software
20130407Sdfr *    without specific prior written permission.
21130407Sdfr *
22130407Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23130407Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24130407Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25130407Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26130407Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27130407Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28130407Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29130407Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30130407Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31130407Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32130407Sdfr * SUCH DAMAGE.
33130407Sdfr *
34130407Sdfr * $FreeBSD: head/sys/dev/firewire/fwmem.c 103285 2002-09-13 12:31:56Z ikob $
35130407Sdfr */
36130407Sdfr
37130407Sdfr#include <sys/param.h>
38130407Sdfr#include <sys/systm.h>
39130407Sdfr#include <sys/types.h>
40130407Sdfr
41130407Sdfr#include <sys/kernel.h>
42130407Sdfr#include <sys/malloc.h>
43130407Sdfr#include <sys/conf.h>
44130407Sdfr#include <sys/uio.h>
45130407Sdfr#include <sys/sysctl.h>
46130407Sdfr
47130407Sdfr#include <sys/bus.h>
48130407Sdfr
49130407Sdfr#include <sys/signal.h>
50130407Sdfr#include <sys/mman.h>
51130407Sdfr#include <sys/ioccom.h>
52130407Sdfr
53130407Sdfr#include <dev/firewire/firewire.h>
54130407Sdfr#include <dev/firewire/firewirereg.h>
55130407Sdfr#include <dev/firewire/fwmem.h>
56130407Sdfr
57130407Sdfrstatic int fwmem_node=0, fwmem_speed=2, fwmem_debug=0;
58130407SdfrSYSCTL_DECL(_hw_firewire);
59130407SdfrSYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
60130407Sdfr	"Firewire Memory Access");
61130407SdfrSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, node, CTLFLAG_RW, &fwmem_node, 0,
62130407Sdfr	"Fwmem target node");
63130407SdfrSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
64130407Sdfr	"Fwmem link speed");
65130407SdfrSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
66130407Sdfr	"Fwmem driver debug flag");
67130407Sdfr
68130407Sdfrstruct fw_xfer *
69130407Sdfrfwmem_read_quad(
70130407Sdfr	struct firewire_comm *fc,
71130407Sdfr	int dst,
72130407Sdfr	u_int16_t dst_hi,
73130407Sdfr	u_int32_t dst_lo
74130407Sdfr	)
75130407Sdfr{
76130407Sdfr	struct fw_xfer *xfer;
77130407Sdfr	struct fw_pkt *fp;
78130407Sdfr	int err = 0;
79130407Sdfr
80130407Sdfr	xfer = fw_xfer_alloc();
81130407Sdfr	if (xfer == NULL) {
82130407Sdfr		err = ENOMEM;
83130407Sdfr		return NULL;
84130407Sdfr	}
85130407Sdfr	xfer->fc = fc;
86130407Sdfr	xfer->dst = FWLOCALBUS | dst;
87130407Sdfr	xfer->spd = fwmem_speed; /* XXX */
88130407Sdfr	xfer->send.len = 12;
89130407Sdfr	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
90130407Sdfr	if (xfer->send.buf == NULL) {
91130407Sdfr		err = ENOMEM;
92130407Sdfr		goto error;
93130407Sdfr	}
94130407Sdfr	xfer->send.off = 0;
95130407Sdfr	xfer->act.hand = fw_asy_callback;
96130407Sdfr	xfer->retry_req = fw_asybusy;
97130407Sdfr	xfer->sc = NULL;
98130407Sdfr
99130407Sdfr	fp = (struct fw_pkt *)xfer->send.buf;
100130407Sdfr	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
101130407Sdfr	fp->mode.rreqq.dst = htons(xfer->dst);
102130407Sdfr	fp->mode.rreqq.dest_hi = htons(dst_hi);
103130407Sdfr	fp->mode.rreqq.dest_lo = htonl(dst_lo);
104130407Sdfr
105130407Sdfr	if (fwmem_debug)
106130407Sdfr		printf("fwmem: %d %04x:%08x\n", dst, dst_hi, dst_lo);
107130407Sdfr	err = fw_asyreq(fc, -1, xfer);
108130407Sdfr	if (err)
109130407Sdfr		goto error;
110130407Sdfr	err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
111130407Sdfr	if (err == 0) {
112130407Sdfr		return xfer;
113130407Sdfr	}
114130407Sdfrerror:
115130407Sdfr	fw_xfer_free(xfer);
116130407Sdfr	return NULL;
117130407Sdfr}
118130407Sdfr
119130407Sdfrstruct fw_xfer *
120130407Sdfrfwmem_read_block(
121130407Sdfr	struct firewire_comm *fc,
122130407Sdfr	int dst,
123130407Sdfr	u_int16_t dst_hi,
124130407Sdfr	u_int32_t dst_lo,
125130407Sdfr	int len
126130407Sdfr	)
127130407Sdfr{
128130407Sdfr	struct fw_xfer *xfer;
129130407Sdfr	struct fw_pkt *fp;
130130407Sdfr	int err = 0;
131130407Sdfr
132130407Sdfr	xfer = fw_xfer_alloc();
133130407Sdfr	if (xfer == NULL) {
134130407Sdfr		err = ENOMEM;
135130407Sdfr		return NULL;
136130407Sdfr	}
137130407Sdfr	xfer->fc = fc;
138130407Sdfr	xfer->dst = FWLOCALBUS | dst;
139130407Sdfr	xfer->spd = fwmem_speed;	/* XXX */
140130407Sdfr	xfer->send.len = 16;
141130407Sdfr	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
142130407Sdfr	if (xfer->send.buf == NULL) {
143130407Sdfr		err = ENOMEM;
144130407Sdfr		goto error;
145130407Sdfr	}
146130407Sdfr	xfer->send.off = 0;
147130407Sdfr	xfer->act.hand = fw_asy_callback;
148130407Sdfr	xfer->retry_req = fw_asybusy;
149130407Sdfr	xfer->sc = NULL;
150130407Sdfr
151130407Sdfr	fp = (struct fw_pkt *)xfer->send.buf;
152130407Sdfr	fp->mode.rreqb.tcode = FWTCODE_RREQB;
153130407Sdfr	fp->mode.rreqb.dst = htons(xfer->dst);
154130407Sdfr	fp->mode.rreqb.dest_hi = htons(dst_hi);
155130407Sdfr	fp->mode.rreqb.dest_lo = htonl(dst_lo);
156130407Sdfr	fp->mode.rreqb.len = htons(len);
157130407Sdfr
158130407Sdfr	if (fwmem_debug)
159130407Sdfr		printf("fwmem: %d %04x:%08x %d\n", dst, dst_hi, dst_lo, len);
160130407Sdfr	err = fw_asyreq(fc, -1, xfer);
161130407Sdfr	if (err)
162130407Sdfr		goto error;
163130407Sdfr	err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
164130407Sdfr	if (err == 0) {
165130407Sdfr		return xfer;
166130407Sdfr	}
167130407Sdfrerror:
168130407Sdfr	fw_xfer_free(xfer);
169130407Sdfr	return NULL;
170130407Sdfr}
171130407Sdfr
172130407Sdfrint
173130407Sdfrfwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
174130407Sdfr{
175130407Sdfr	int err = 0;
176130407Sdfr	return err;
177130407Sdfr}
178130407Sdfr
179130407Sdfrint
180130407Sdfrfwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
181130407Sdfr{
182130407Sdfr	int err = 0;
183130407Sdfr	return err;
184130407Sdfr}
185130407Sdfr
186130407Sdfr#define MAXLEN 2048
187130407Sdfr#define USE_QUAD 0
188130407Sdfrint
189130407Sdfrfwmem_read (dev_t dev, struct uio *uio, int ioflag)
190130407Sdfr{
191130407Sdfr	struct firewire_softc *sc;
192130407Sdfr	struct firewire_comm *fc;
193130407Sdfr	struct fw_xfer *xfer;
194130407Sdfr	int err = 0, pad;
195130407Sdfr        int unit = DEV2UNIT(dev);
196130407Sdfr	u_int16_t dst_hi;
197130407Sdfr	u_int32_t dst_lo;
198130407Sdfr	off_t offset;
199130407Sdfr	int len;
200130407Sdfr
201130407Sdfr	sc = devclass_get_softc(firewire_devclass, unit);
202130407Sdfr	fc = sc->fc;
203130407Sdfr
204130407Sdfr	pad = uio->uio_offset % 4;
205130407Sdfr	if  (fwmem_debug && pad != 0)
206130407Sdfr		printf("unaligned\n");
207130407Sdfr	while(uio->uio_resid > 0) {
208130407Sdfr		offset = uio->uio_offset;
209130407Sdfr		offset -= pad;
210130407Sdfr		dst_hi = (offset >> 32) & 0xffff;
211130407Sdfr		dst_lo = offset & 0xffffffff;
212130407Sdfr#if USE_QUAD
213130407Sdfr		xfer = fwmem_read_quad(fc, fwmem_node, dst_hi, dst_lo);
214130407Sdfr		if (xfer == NULL || xfer->resp != 0 || xfer->recv.buf == NULL)
215130407Sdfr			return EINVAL; /* XXX */
216130407Sdfr		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*3 + pad,
217130407Sdfr			4 - pad, uio);
218130407Sdfr#else
219130407Sdfr		len = uio->uio_resid;
220130407Sdfr		if (len > MAXLEN)
221130407Sdfr			len = MAXLEN;
222130407Sdfr		xfer = fwmem_read_block(fc, fwmem_node, dst_hi, dst_lo, len);
223130407Sdfr		if (xfer == NULL || xfer->resp != 0 || xfer->recv.buf == NULL)
224130407Sdfr			return EINVAL; /* XXX */
225130407Sdfr		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*4 + pad,
226130407Sdfr			len - pad, uio);
227130407Sdfr#endif
228130407Sdfr		if (err)
229130407Sdfr			return err;
230130407Sdfr		fw_xfer_free(xfer);
231130407Sdfr		pad = 0;
232130407Sdfr	}
233130407Sdfr	return err;
234130407Sdfr}
235130407Sdfrint
236130407Sdfrfwmem_write (dev_t dev, struct uio *uio, int ioflag)
237130407Sdfr{
238130407Sdfr	return EINVAL;
239130407Sdfr}
240130407Sdfrint
241130407Sdfrfwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
242130407Sdfr{
243130407Sdfr	return EINVAL;
244130407Sdfr}
245130407Sdfrint
246130407Sdfrfwmem_poll (dev_t dev, int events, fw_proc *td)
247130407Sdfr{
248130407Sdfr	return EINVAL;
249130407Sdfr}
250130407Sdfrint
251130407Sdfrfwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
252130407Sdfr{
253130407Sdfr	return EINVAL;
254130407Sdfr}
255130407Sdfr