fwmem.c revision 106804
1/*
2 * Copyright (C) 2002
3 * 	Hidetoshi Shimokawa. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *
16 *	This product includes software developed by Hidetoshi Shimokawa.
17 *
18 * 4. Neither the name of the author nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * $FreeBSD: head/sys/dev/firewire/fwmem.c 106804 2002-11-12 11:08:50Z simokawa $
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/types.h>
40
41#include <sys/kernel.h>
42#include <sys/malloc.h>
43#include <sys/conf.h>
44#include <sys/uio.h>
45#include <sys/sysctl.h>
46
47#include <sys/bus.h>
48
49#include <sys/signal.h>
50#include <sys/mman.h>
51#include <sys/ioccom.h>
52
53#include <dev/firewire/firewire.h>
54#include <dev/firewire/firewirereg.h>
55#include <dev/firewire/fwmem.h>
56
57static int fwmem_node=0, fwmem_speed=2, fwmem_debug=0;
58SYSCTL_DECL(_hw_firewire);
59SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
60	"Firewire Memory Access");
61SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, node, CTLFLAG_RW, &fwmem_node, 0,
62	"Fwmem target node");
63SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
64	"Fwmem link speed");
65SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
66	"Fwmem driver debug flag");
67
68struct fw_xfer *
69fwmem_read_quad(
70	struct firewire_comm *fc,
71	u_int8_t spd,
72	int dst,
73	u_int16_t dst_hi,
74	u_int32_t dst_lo,
75	void (*hand)(struct fw_xfer *))
76{
77	struct fw_xfer *xfer;
78	struct fw_pkt *fp;
79
80	xfer = fw_xfer_alloc();
81	if (xfer == NULL)
82		return NULL;
83
84	xfer->fc = fc;
85	xfer->dst = FWLOCALBUS | dst;
86	xfer->spd = spd;
87	xfer->send.len = 12;
88	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
89
90	if (xfer->send.buf == NULL)
91		goto error;
92
93	xfer->send.off = 0;
94	xfer->act.hand = hand;
95	xfer->retry_req = fw_asybusy;
96	xfer->sc = NULL;
97
98	fp = (struct fw_pkt *)xfer->send.buf;
99	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
100	fp->mode.rreqq.dst = htons(xfer->dst);
101	fp->mode.rreqq.dest_hi = htons(dst_hi);
102	fp->mode.rreqq.dest_lo = htonl(dst_lo);
103
104	if (fwmem_debug)
105		printf("fwmem: %d %04x:%08x\n", dst, dst_hi, dst_lo);
106
107	if (fw_asyreq(fc, -1, xfer) == 0)
108		return xfer;
109
110error:
111	fw_xfer_free(xfer);
112	return NULL;
113}
114
115struct fw_xfer *
116fwmem_read_block(
117	struct firewire_comm *fc,
118	u_int8_t spd,
119	int dst,
120	u_int16_t dst_hi,
121	u_int32_t dst_lo,
122	int len,
123	void (*hand)(struct fw_xfer *))
124{
125	struct fw_xfer *xfer;
126	struct fw_pkt *fp;
127
128	xfer = fw_xfer_alloc();
129	if (xfer == NULL)
130		return NULL;
131
132	xfer->fc = fc;
133	xfer->dst = FWLOCALBUS | dst;
134	xfer->spd = spd;
135	xfer->send.len = 16;
136	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
137
138	if (xfer->send.buf == NULL)
139		goto error;
140
141	xfer->send.off = 0;
142	xfer->act.hand = fw_asy_callback;
143	xfer->retry_req = fw_asybusy;
144	xfer->sc = NULL;
145
146	fp = (struct fw_pkt *)xfer->send.buf;
147	fp->mode.rreqb.tcode = FWTCODE_RREQB;
148	fp->mode.rreqb.dst = htons(xfer->dst);
149	fp->mode.rreqb.dest_hi = htons(dst_hi);
150	fp->mode.rreqb.dest_lo = htonl(dst_lo);
151	fp->mode.rreqb.len = htons(len);
152
153	if (fwmem_debug)
154		printf("fwmem: %d %04x:%08x %d\n", dst, dst_hi, dst_lo, len);
155	if (fw_asyreq(fc, -1, xfer) == 0)
156		return xfer;
157
158error:
159	fw_xfer_free(xfer);
160	return NULL;
161}
162
163int
164fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
165{
166	int err = 0;
167	return err;
168}
169
170int
171fwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
172{
173	int err = 0;
174	return err;
175}
176
177#define MAXLEN 2048
178#define USE_QUAD 0
179int
180fwmem_read (dev_t dev, struct uio *uio, int ioflag)
181{
182	struct firewire_softc *sc;
183	struct firewire_comm *fc;
184	struct fw_xfer *xfer;
185	int err = 0, pad;
186        int unit = DEV2UNIT(dev);
187	u_int16_t dst_hi;
188	u_int32_t dst_lo;
189	off_t offset;
190	int len;
191
192	sc = devclass_get_softc(firewire_devclass, unit);
193	fc = sc->fc;
194
195	pad = uio->uio_offset % 4;
196	if  (fwmem_debug && pad != 0)
197		printf("unaligned\n");
198	while(uio->uio_resid > 0) {
199		offset = uio->uio_offset;
200		offset -= pad;
201		dst_hi = (offset >> 32) & 0xffff;
202		dst_lo = offset & 0xffffffff;
203#if USE_QUAD
204		xfer = fwmem_read_quad(fc, fwmem_speed, fwmem_node,
205				dst_hi, dst_lo, fw_asy_callback);
206		if (xfer == NULL)
207			return EINVAL;
208		err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
209		if (err !=0 || xfer->resp != 0 || xfer->recv.buf == NULL)
210			return EINVAL; /* XXX */
211		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*3 + pad,
212			4 - pad, uio);
213#else
214		len = uio->uio_resid;
215		if (len > MAXLEN)
216			len = MAXLEN;
217		xfer = fwmem_read_block(fc, fwmem_speed, fwmem_node,
218				dst_hi, dst_lo, len, fw_asy_callback);
219		if (xfer == NULL)
220			return EINVAL;
221		err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
222		if (err != 0 || xfer->resp != 0 || xfer->recv.buf == NULL)
223			return EINVAL; /* XXX */
224		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*4 + pad,
225			len - pad, uio);
226#endif
227		if (err)
228			return err;
229		fw_xfer_free(xfer);
230		pad = 0;
231	}
232	return err;
233}
234int
235fwmem_write (dev_t dev, struct uio *uio, int ioflag)
236{
237	return EINVAL;
238}
239int
240fwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
241{
242	return EINVAL;
243}
244int
245fwmem_poll (dev_t dev, int events, fw_proc *td)
246{
247	return EINVAL;
248}
249int
250fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
251{
252	return EINVAL;
253}
254