fwmem.c revision 106810
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 106810 2002-11-12 13:49:17Z 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_speed=2, fwmem_debug=0;
58static struct fw_eui64 fwmem_eui64;
59SYSCTL_DECL(_hw_firewire);
60SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
61	"Firewire Memory Access");
62SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
63	&fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
64SYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_low, CTLFLAG_RW,
65	&fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
66SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
67	"Fwmem link speed");
68SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
69	"Fwmem driver debug flag");
70
71struct fw_xfer *
72fwmem_read_quad(
73	struct fw_device *fwdev,
74	caddr_t	sc,
75	u_int8_t spd,
76	u_int16_t dst_hi,
77	u_int32_t dst_lo,
78	void (*hand)(struct fw_xfer *))
79{
80	struct fw_xfer *xfer;
81	struct fw_pkt *fp;
82
83	xfer = fw_xfer_alloc();
84	if (xfer == NULL)
85		return NULL;
86
87	xfer->fc = fwdev->fc;
88	xfer->dst = FWLOCALBUS | fwdev->dst;
89	xfer->spd = spd;
90	xfer->send.len = 12;
91	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
92
93	if (xfer->send.buf == NULL)
94		goto error;
95
96	xfer->send.off = 0;
97	xfer->act.hand = hand;
98	xfer->retry_req = fw_asybusy;
99	xfer->sc = NULL;
100
101	fp = (struct fw_pkt *)xfer->send.buf;
102	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
103	fp->mode.rreqq.dst = htons(xfer->dst);
104	fp->mode.rreqq.dest_hi = htons(dst_hi);
105	fp->mode.rreqq.dest_lo = htonl(dst_lo);
106
107	if (fwmem_debug)
108		printf("fwmem: %d %04x:%08x\n", fwdev->dst, dst_hi, dst_lo);
109
110	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
111		return xfer;
112
113error:
114	fw_xfer_free(xfer);
115	return NULL;
116}
117
118struct fw_xfer *
119fwmem_write_quad(
120	struct fw_device *fwdev,
121	caddr_t	sc,
122	u_int8_t spd,
123	u_int16_t dst_hi,
124	u_int32_t dst_lo,
125	u_int32_t data,
126	void (*hand)(struct fw_xfer *))
127{
128	struct fw_xfer *xfer;
129	struct fw_pkt *fp;
130
131	xfer = fw_xfer_alloc();
132	if (xfer == NULL)
133		return NULL;
134
135	xfer->fc = fwdev->fc;
136	xfer->dst = FWLOCALBUS | fwdev->dst;
137	xfer->spd = spd;
138	xfer->send.len = 16;
139	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
140
141	if (xfer->send.buf == NULL)
142		goto error;
143
144	xfer->send.off = 0;
145	xfer->act.hand = hand;
146	xfer->retry_req = fw_asybusy;
147	xfer->sc = sc;
148
149	fp = (struct fw_pkt *)xfer->send.buf;
150	fp->mode.wreqq.tcode = FWTCODE_RREQQ;
151	fp->mode.wreqq.dst = htons(xfer->dst);
152	fp->mode.wreqq.dest_hi = htons(dst_hi);
153	fp->mode.wreqq.dest_lo = htonl(dst_lo);
154
155	fp->mode.wreqq.data = htonl(data);
156
157	if (fwmem_debug)
158		printf("fwmem: %d %04x:%08x\n", fwdev->dst, dst_hi, dst_lo);
159
160	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
161		return xfer;
162
163error:
164	fw_xfer_free(xfer);
165	return NULL;
166}
167
168struct fw_xfer *
169fwmem_read_block(
170	struct fw_device *fwdev,
171	caddr_t	sc,
172	u_int8_t spd,
173	u_int16_t dst_hi,
174	u_int32_t dst_lo,
175	int len,
176	void (*hand)(struct fw_xfer *))
177{
178	struct fw_xfer *xfer;
179	struct fw_pkt *fp;
180
181	xfer = fw_xfer_alloc();
182	if (xfer == NULL)
183		return NULL;
184
185	xfer->fc = fwdev->fc;
186	xfer->dst = FWLOCALBUS | fwdev->dst;
187	xfer->spd = spd;
188	xfer->send.len = 16;
189	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
190
191	if (xfer->send.buf == NULL)
192		goto error;
193
194	xfer->send.off = 0;
195	xfer->act.hand = fw_asy_callback;
196	xfer->retry_req = fw_asybusy;
197	xfer->sc = NULL;
198
199	fp = (struct fw_pkt *)xfer->send.buf;
200	fp->mode.rreqb.tcode = FWTCODE_RREQB;
201	fp->mode.rreqb.dst = htons(xfer->dst);
202	fp->mode.rreqb.dest_hi = htons(dst_hi);
203	fp->mode.rreqb.dest_lo = htonl(dst_lo);
204	fp->mode.rreqb.len = htons(len);
205
206	if (fwmem_debug)
207		printf("fwmem: %d %04x:%08x %d\n", fwdev->dst,
208				dst_hi, dst_lo, len);
209	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
210		return xfer;
211
212error:
213	fw_xfer_free(xfer);
214	return NULL;
215}
216
217int
218fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
219{
220	int err = 0;
221	return err;
222}
223
224int
225fwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
226{
227	int err = 0;
228	return err;
229}
230
231#define MAXLEN 2048
232#define USE_QUAD 0
233int
234fwmem_read (dev_t dev, struct uio *uio, int ioflag)
235{
236	struct firewire_softc *sc;
237	struct fw_device *fwdev;
238	struct fw_xfer *xfer;
239	int err = 0, pad;
240        int unit = DEV2UNIT(dev);
241	u_int16_t dst_hi;
242	u_int32_t dst_lo;
243	off_t offset;
244	int len;
245
246	sc = devclass_get_softc(firewire_devclass, unit);
247	fwdev = fw_noderesolve(sc->fc, fwmem_eui64);
248	if (fwdev == NULL) {
249		printf("fwmem: no such device ID:%08x%08x\n",
250			fwmem_eui64.hi, fwmem_eui64.lo);
251		return EINVAL;
252	}
253
254	pad = uio->uio_offset % 4;
255	if  (fwmem_debug && pad != 0)
256		printf("unaligned\n");
257	while(uio->uio_resid > 0) {
258		offset = uio->uio_offset;
259		offset -= pad;
260		dst_hi = (offset >> 32) & 0xffff;
261		dst_lo = offset & 0xffffffff;
262#if USE_QUAD
263		xfer = fwmem_read_quad(fwdev, NULL, fwmem_speed,
264				dst_hi, dst_lo, fw_asy_callback);
265		if (xfer == NULL)
266			return EINVAL;
267		err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
268		if (err !=0 || xfer->resp != 0 || xfer->recv.buf == NULL)
269			return EINVAL; /* XXX */
270		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*3 + pad,
271			4 - pad, uio);
272#else
273		len = uio->uio_resid;
274		if (len > MAXLEN)
275			len = MAXLEN;
276		xfer = fwmem_read_block(fwdev, NULL, fwmem_speed,
277				dst_hi, dst_lo, len, fw_asy_callback);
278		if (xfer == NULL)
279			return EINVAL;
280		err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
281		if (err != 0 || xfer->resp != 0 || xfer->recv.buf == NULL)
282			return EINVAL; /* XXX */
283		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*4 + pad,
284			len - pad, uio);
285#endif
286		if (err)
287			return err;
288		fw_xfer_free(xfer);
289		pad = 0;
290	}
291	return err;
292}
293int
294fwmem_write (dev_t dev, struct uio *uio, int ioflag)
295{
296	return EINVAL;
297}
298int
299fwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
300{
301	return EINVAL;
302}
303int
304fwmem_poll (dev_t dev, int events, fw_proc *td)
305{
306	return EINVAL;
307}
308int
309fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
310{
311	return EINVAL;
312}
313