fwmem.c revision 108281
1103285Sikob/*
2103285Sikob * Copyright (C) 2002
3103285Sikob * 	Hidetoshi Shimokawa. All rights reserved.
4103285Sikob *
5103285Sikob * Redistribution and use in source and binary forms, with or without
6103285Sikob * modification, are permitted provided that the following conditions
7103285Sikob * are met:
8103285Sikob * 1. Redistributions of source code must retain the above copyright
9103285Sikob *    notice, this list of conditions and the following disclaimer.
10103285Sikob * 2. Redistributions in binary form must reproduce the above copyright
11103285Sikob *    notice, this list of conditions and the following disclaimer in the
12103285Sikob *    documentation and/or other materials provided with the distribution.
13103285Sikob * 3. All advertising materials mentioning features or use of this software
14103285Sikob *    must display the following acknowledgement:
15103285Sikob *
16103285Sikob *	This product includes software developed by Hidetoshi Shimokawa.
17103285Sikob *
18103285Sikob * 4. Neither the name of the author nor the names of its contributors
19103285Sikob *    may be used to endorse or promote products derived from this software
20103285Sikob *    without specific prior written permission.
21103285Sikob *
22103285Sikob * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24103285Sikob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25103285Sikob * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26103285Sikob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27103285Sikob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28103285Sikob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30103285Sikob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32103285Sikob * SUCH DAMAGE.
33103285Sikob *
34103285Sikob * $FreeBSD: head/sys/dev/firewire/fwmem.c 108281 2002-12-26 06:50:09Z simokawa $
35103285Sikob */
36103285Sikob
37103285Sikob#include <sys/param.h>
38103285Sikob#include <sys/systm.h>
39103285Sikob#include <sys/types.h>
40103285Sikob
41103285Sikob#include <sys/kernel.h>
42103285Sikob#include <sys/malloc.h>
43103285Sikob#include <sys/conf.h>
44103285Sikob#include <sys/uio.h>
45103285Sikob#include <sys/sysctl.h>
46103285Sikob
47103285Sikob#include <sys/bus.h>
48103285Sikob
49103285Sikob#include <sys/signal.h>
50103285Sikob#include <sys/mman.h>
51103285Sikob#include <sys/ioccom.h>
52103285Sikob
53103285Sikob#include <dev/firewire/firewire.h>
54103285Sikob#include <dev/firewire/firewirereg.h>
55103285Sikob#include <dev/firewire/fwmem.h>
56103285Sikob
57106810Ssimokawastatic int fwmem_speed=2, fwmem_debug=0;
58106810Ssimokawastatic struct fw_eui64 fwmem_eui64;
59103285SikobSYSCTL_DECL(_hw_firewire);
60103285SikobSYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
61108281Ssimokawa	"FireWire Memory Access");
62106810SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
63106810Ssimokawa	&fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
64106810SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_low, CTLFLAG_RW,
65106810Ssimokawa	&fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
66103285SikobSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
67103285Sikob	"Fwmem link speed");
68103285SikobSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
69103285Sikob	"Fwmem driver debug flag");
70103285Sikob
71106816Ssimokawastatic struct fw_xfer *fwmem_xfer_req(struct fw_device *, caddr_t,
72106816Ssimokawa							int, int, void *);
73106816Ssimokawa
74106816Ssimokawastatic struct fw_xfer *
75106816Ssimokawafwmem_xfer_req(
76106810Ssimokawa	struct fw_device *fwdev,
77106816Ssimokawa	caddr_t sc,
78106816Ssimokawa	int spd,
79106816Ssimokawa	int len,
80106816Ssimokawa	void *hand)
81103285Sikob{
82103285Sikob	struct fw_xfer *xfer;
83103285Sikob
84103285Sikob	xfer = fw_xfer_alloc();
85106804Ssimokawa	if (xfer == NULL)
86103285Sikob		return NULL;
87106804Ssimokawa
88106810Ssimokawa	xfer->fc = fwdev->fc;
89106810Ssimokawa	xfer->dst = FWLOCALBUS | fwdev->dst;
90106816Ssimokawa	if (spd < 0)
91106816Ssimokawa		xfer->spd = fwdev->speed;
92106816Ssimokawa	else
93106816Ssimokawa		xfer->spd = min(spd, fwdev->speed);
94106816Ssimokawa	xfer->send.len = len;
95106816Ssimokawa	xfer->send.buf = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
96106804Ssimokawa
97106816Ssimokawa	if (xfer->send.buf == NULL) {
98106816Ssimokawa		fw_xfer_free(xfer);
99106816Ssimokawa		return NULL;
100106816Ssimokawa	}
101106804Ssimokawa
102103285Sikob	xfer->send.off = 0;
103106804Ssimokawa	xfer->act.hand = hand;
104103285Sikob	xfer->retry_req = fw_asybusy;
105106816Ssimokawa	xfer->sc = sc;
106103285Sikob
107106816Ssimokawa	return xfer;
108106816Ssimokawa}
109106816Ssimokawa
110106816Ssimokawastruct fw_xfer *
111106816Ssimokawafwmem_read_quad(
112106816Ssimokawa	struct fw_device *fwdev,
113106816Ssimokawa	caddr_t	sc,
114106816Ssimokawa	u_int8_t spd,
115106816Ssimokawa	u_int16_t dst_hi,
116106816Ssimokawa	u_int32_t dst_lo,
117106816Ssimokawa	void (*hand)(struct fw_xfer *))
118106816Ssimokawa{
119106816Ssimokawa	struct fw_xfer *xfer;
120106816Ssimokawa	struct fw_pkt *fp;
121106816Ssimokawa
122106816Ssimokawa	xfer = fwmem_xfer_req(fwdev, sc, spd, 12, hand);
123106816Ssimokawa	if (xfer == NULL)
124106816Ssimokawa		return NULL;
125106816Ssimokawa
126103285Sikob	fp = (struct fw_pkt *)xfer->send.buf;
127103285Sikob	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
128103285Sikob	fp->mode.rreqq.dst = htons(xfer->dst);
129103285Sikob	fp->mode.rreqq.dest_hi = htons(dst_hi);
130103285Sikob	fp->mode.rreqq.dest_lo = htonl(dst_lo);
131103285Sikob
132103285Sikob	if (fwmem_debug)
133106816Ssimokawa		printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
134106816Ssimokawa				dst_hi, dst_lo);
135106804Ssimokawa
136106810Ssimokawa	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
137103285Sikob		return xfer;
138106804Ssimokawa
139103285Sikob	fw_xfer_free(xfer);
140103285Sikob	return NULL;
141103285Sikob}
142103285Sikob
143103285Sikobstruct fw_xfer *
144106810Ssimokawafwmem_write_quad(
145106810Ssimokawa	struct fw_device *fwdev,
146106810Ssimokawa	caddr_t	sc,
147106810Ssimokawa	u_int8_t spd,
148106810Ssimokawa	u_int16_t dst_hi,
149106810Ssimokawa	u_int32_t dst_lo,
150106810Ssimokawa	u_int32_t data,
151106810Ssimokawa	void (*hand)(struct fw_xfer *))
152106810Ssimokawa{
153106810Ssimokawa	struct fw_xfer *xfer;
154106810Ssimokawa	struct fw_pkt *fp;
155106810Ssimokawa
156106816Ssimokawa	xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand);
157106810Ssimokawa	if (xfer == NULL)
158106810Ssimokawa		return NULL;
159106810Ssimokawa
160106810Ssimokawa	fp = (struct fw_pkt *)xfer->send.buf;
161106810Ssimokawa	fp->mode.wreqq.tcode = FWTCODE_RREQQ;
162106810Ssimokawa	fp->mode.wreqq.dst = htons(xfer->dst);
163106810Ssimokawa	fp->mode.wreqq.dest_hi = htons(dst_hi);
164106810Ssimokawa	fp->mode.wreqq.dest_lo = htonl(dst_lo);
165106810Ssimokawa
166106810Ssimokawa	fp->mode.wreqq.data = htonl(data);
167106810Ssimokawa
168106810Ssimokawa	if (fwmem_debug)
169106816Ssimokawa		printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
170106816Ssimokawa			dst_hi, dst_lo, data);
171106810Ssimokawa
172106810Ssimokawa	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
173106810Ssimokawa		return xfer;
174106810Ssimokawa
175106810Ssimokawa	fw_xfer_free(xfer);
176106810Ssimokawa	return NULL;
177106810Ssimokawa}
178106810Ssimokawa
179106810Ssimokawastruct fw_xfer *
180103285Sikobfwmem_read_block(
181106810Ssimokawa	struct fw_device *fwdev,
182106810Ssimokawa	caddr_t	sc,
183106804Ssimokawa	u_int8_t spd,
184103285Sikob	u_int16_t dst_hi,
185103285Sikob	u_int32_t dst_lo,
186106804Ssimokawa	int len,
187106804Ssimokawa	void (*hand)(struct fw_xfer *))
188103285Sikob{
189103285Sikob	struct fw_xfer *xfer;
190103285Sikob	struct fw_pkt *fp;
191103285Sikob
192106816Ssimokawa	xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand);
193106804Ssimokawa	if (xfer == NULL)
194103285Sikob		return NULL;
195106804Ssimokawa
196103285Sikob	fp = (struct fw_pkt *)xfer->send.buf;
197103285Sikob	fp->mode.rreqb.tcode = FWTCODE_RREQB;
198103285Sikob	fp->mode.rreqb.dst = htons(xfer->dst);
199103285Sikob	fp->mode.rreqb.dest_hi = htons(dst_hi);
200103285Sikob	fp->mode.rreqb.dest_lo = htonl(dst_lo);
201103285Sikob	fp->mode.rreqb.len = htons(len);
202103285Sikob
203103285Sikob	if (fwmem_debug)
204106816Ssimokawa		printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
205106810Ssimokawa				dst_hi, dst_lo, len);
206106810Ssimokawa	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
207103285Sikob		return xfer;
208106804Ssimokawa
209103285Sikob	fw_xfer_free(xfer);
210103285Sikob	return NULL;
211103285Sikob}
212103285Sikob
213103285Sikobint
214103285Sikobfwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
215103285Sikob{
216103285Sikob	int err = 0;
217103285Sikob	return err;
218103285Sikob}
219103285Sikob
220103285Sikobint
221103285Sikobfwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
222103285Sikob{
223103285Sikob	int err = 0;
224103285Sikob	return err;
225103285Sikob}
226103285Sikob
227103285Sikob#define MAXLEN 2048
228103285Sikob#define USE_QUAD 0
229103285Sikobint
230103285Sikobfwmem_read (dev_t dev, struct uio *uio, int ioflag)
231103285Sikob{
232103285Sikob	struct firewire_softc *sc;
233106810Ssimokawa	struct fw_device *fwdev;
234103285Sikob	struct fw_xfer *xfer;
235103285Sikob	int err = 0, pad;
236103285Sikob        int unit = DEV2UNIT(dev);
237103285Sikob	u_int16_t dst_hi;
238103285Sikob	u_int32_t dst_lo;
239103285Sikob	off_t offset;
240103285Sikob	int len;
241103285Sikob
242103285Sikob	sc = devclass_get_softc(firewire_devclass, unit);
243106810Ssimokawa	fwdev = fw_noderesolve(sc->fc, fwmem_eui64);
244106810Ssimokawa	if (fwdev == NULL) {
245106810Ssimokawa		printf("fwmem: no such device ID:%08x%08x\n",
246106810Ssimokawa			fwmem_eui64.hi, fwmem_eui64.lo);
247106810Ssimokawa		return EINVAL;
248106810Ssimokawa	}
249103285Sikob
250103285Sikob	pad = uio->uio_offset % 4;
251103285Sikob	if  (fwmem_debug && pad != 0)
252103285Sikob		printf("unaligned\n");
253103285Sikob	while(uio->uio_resid > 0) {
254103285Sikob		offset = uio->uio_offset;
255103285Sikob		offset -= pad;
256103285Sikob		dst_hi = (offset >> 32) & 0xffff;
257103285Sikob		dst_lo = offset & 0xffffffff;
258103285Sikob#if USE_QUAD
259106810Ssimokawa		xfer = fwmem_read_quad(fwdev, NULL, fwmem_speed,
260106804Ssimokawa				dst_hi, dst_lo, fw_asy_callback);
261106804Ssimokawa		if (xfer == NULL)
262106804Ssimokawa			return EINVAL;
263106804Ssimokawa		err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
264106804Ssimokawa		if (err !=0 || xfer->resp != 0 || xfer->recv.buf == NULL)
265103285Sikob			return EINVAL; /* XXX */
266103285Sikob		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*3 + pad,
267103285Sikob			4 - pad, uio);
268103285Sikob#else
269103285Sikob		len = uio->uio_resid;
270103285Sikob		if (len > MAXLEN)
271103285Sikob			len = MAXLEN;
272106810Ssimokawa		xfer = fwmem_read_block(fwdev, NULL, fwmem_speed,
273106804Ssimokawa				dst_hi, dst_lo, len, fw_asy_callback);
274106804Ssimokawa		if (xfer == NULL)
275106804Ssimokawa			return EINVAL;
276106804Ssimokawa		err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
277106804Ssimokawa		if (err != 0 || xfer->resp != 0 || xfer->recv.buf == NULL)
278103285Sikob			return EINVAL; /* XXX */
279103285Sikob		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*4 + pad,
280103285Sikob			len - pad, uio);
281103285Sikob#endif
282103285Sikob		if (err)
283103285Sikob			return err;
284103285Sikob		fw_xfer_free(xfer);
285103285Sikob		pad = 0;
286103285Sikob	}
287103285Sikob	return err;
288103285Sikob}
289103285Sikobint
290103285Sikobfwmem_write (dev_t dev, struct uio *uio, int ioflag)
291103285Sikob{
292103285Sikob	return EINVAL;
293103285Sikob}
294103285Sikobint
295103285Sikobfwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
296103285Sikob{
297103285Sikob	return EINVAL;
298103285Sikob}
299103285Sikobint
300103285Sikobfwmem_poll (dev_t dev, int events, fw_proc *td)
301103285Sikob{
302103285Sikob	return EINVAL;
303103285Sikob}
304103285Sikobint
305103285Sikobfwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
306103285Sikob{
307103285Sikob	return EINVAL;
308103285Sikob}
309