xref: /freebsd/sys/dev/firewire/fwmem.c (revision a3e8fd0b7f663db7eafff527d5c3ca3bcfa8a537)
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$
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 
57 static int fwmem_node=0, fwmem_speed=2, fwmem_debug=0;
58 SYSCTL_DECL(_hw_firewire);
59 SYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
60 	"Firewire Memory Access");
61 SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, node, CTLFLAG_RW, &fwmem_node, 0,
62 	"Fwmem target node");
63 SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
64 	"Fwmem link speed");
65 SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
66 	"Fwmem driver debug flag");
67 
68 struct fw_xfer *
69 fwmem_read_quad(
70 	struct firewire_comm *fc,
71 	int dst,
72 	u_int16_t dst_hi,
73 	u_int32_t dst_lo
74 	)
75 {
76 	struct fw_xfer *xfer;
77 	struct fw_pkt *fp;
78 	int err = 0;
79 
80 	xfer = fw_xfer_alloc();
81 	if (xfer == NULL) {
82 		err = ENOMEM;
83 		return NULL;
84 	}
85 	xfer->fc = fc;
86 	xfer->dst = FWLOCALBUS | dst;
87 	xfer->spd = fwmem_speed; /* XXX */
88 	xfer->send.len = 12;
89 	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
90 	if (xfer->send.buf == NULL) {
91 		err = ENOMEM;
92 		goto error;
93 	}
94 	xfer->send.off = 0;
95 	xfer->act.hand = fw_asy_callback;
96 	xfer->retry_req = fw_asybusy;
97 	xfer->sc = NULL;
98 
99 	fp = (struct fw_pkt *)xfer->send.buf;
100 	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
101 	fp->mode.rreqq.dst = htons(xfer->dst);
102 	fp->mode.rreqq.dest_hi = htons(dst_hi);
103 	fp->mode.rreqq.dest_lo = htonl(dst_lo);
104 
105 	if (fwmem_debug)
106 		printf("fwmem: %d %04x:%08x\n", dst, dst_hi, dst_lo);
107 	err = fw_asyreq(fc, -1, xfer);
108 	if (err)
109 		goto error;
110 	err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
111 	if (err == 0) {
112 		return xfer;
113 	}
114 error:
115 	fw_xfer_free(xfer);
116 	return NULL;
117 }
118 
119 struct fw_xfer *
120 fwmem_read_block(
121 	struct firewire_comm *fc,
122 	int dst,
123 	u_int16_t dst_hi,
124 	u_int32_t dst_lo,
125 	int len
126 	)
127 {
128 	struct fw_xfer *xfer;
129 	struct fw_pkt *fp;
130 	int err = 0;
131 
132 	xfer = fw_xfer_alloc();
133 	if (xfer == NULL) {
134 		err = ENOMEM;
135 		return NULL;
136 	}
137 	xfer->fc = fc;
138 	xfer->dst = FWLOCALBUS | dst;
139 	xfer->spd = fwmem_speed;	/* XXX */
140 	xfer->send.len = 16;
141 	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT | M_ZERO);
142 	if (xfer->send.buf == NULL) {
143 		err = ENOMEM;
144 		goto error;
145 	}
146 	xfer->send.off = 0;
147 	xfer->act.hand = fw_asy_callback;
148 	xfer->retry_req = fw_asybusy;
149 	xfer->sc = NULL;
150 
151 	fp = (struct fw_pkt *)xfer->send.buf;
152 	fp->mode.rreqb.tcode = FWTCODE_RREQB;
153 	fp->mode.rreqb.dst = htons(xfer->dst);
154 	fp->mode.rreqb.dest_hi = htons(dst_hi);
155 	fp->mode.rreqb.dest_lo = htonl(dst_lo);
156 	fp->mode.rreqb.len = htons(len);
157 
158 	if (fwmem_debug)
159 		printf("fwmem: %d %04x:%08x %d\n", dst, dst_hi, dst_lo, len);
160 	err = fw_asyreq(fc, -1, xfer);
161 	if (err)
162 		goto error;
163 	err = tsleep((caddr_t)xfer, FWPRI, "fwmem", hz);
164 	if (err == 0) {
165 		return xfer;
166 	}
167 error:
168 	fw_xfer_free(xfer);
169 	return NULL;
170 }
171 
172 int
173 fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
174 {
175 	int err = 0;
176 	return err;
177 }
178 
179 int
180 fwmem_close (dev_t dev, int flags, int fmt, fw_proc *td)
181 {
182 	int err = 0;
183 	return err;
184 }
185 
186 #define MAXLEN 2048
187 #define USE_QUAD 0
188 int
189 fwmem_read (dev_t dev, struct uio *uio, int ioflag)
190 {
191 	struct firewire_softc *sc;
192 	struct firewire_comm *fc;
193 	struct fw_xfer *xfer;
194 	int err = 0, pad;
195         int unit = DEV2UNIT(dev);
196 	u_int16_t dst_hi;
197 	u_int32_t dst_lo;
198 	off_t offset;
199 	int len;
200 
201 	sc = devclass_get_softc(firewire_devclass, unit);
202 	fc = sc->fc;
203 
204 	pad = uio->uio_offset % 4;
205 	if  (fwmem_debug && pad != 0)
206 		printf("unaligned\n");
207 	while(uio->uio_resid > 0) {
208 		offset = uio->uio_offset;
209 		offset -= pad;
210 		dst_hi = (offset >> 32) & 0xffff;
211 		dst_lo = offset & 0xffffffff;
212 #if USE_QUAD
213 		xfer = fwmem_read_quad(fc, fwmem_node, dst_hi, dst_lo);
214 		if (xfer == NULL || xfer->resp != 0 || xfer->recv.buf == NULL)
215 			return EINVAL; /* XXX */
216 		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*3 + pad,
217 			4 - pad, uio);
218 #else
219 		len = uio->uio_resid;
220 		if (len > MAXLEN)
221 			len = MAXLEN;
222 		xfer = fwmem_read_block(fc, fwmem_node, dst_hi, dst_lo, len);
223 		if (xfer == NULL || xfer->resp != 0 || xfer->recv.buf == NULL)
224 			return EINVAL; /* XXX */
225 		err = uiomove(xfer->recv.buf + xfer->recv.off + 4*4 + pad,
226 			len - pad, uio);
227 #endif
228 		if (err)
229 			return err;
230 		fw_xfer_free(xfer);
231 		pad = 0;
232 	}
233 	return err;
234 }
235 int
236 fwmem_write (dev_t dev, struct uio *uio, int ioflag)
237 {
238 	return EINVAL;
239 }
240 int
241 fwmem_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
242 {
243 	return EINVAL;
244 }
245 int
246 fwmem_poll (dev_t dev, int events, fw_proc *td)
247 {
248 	return EINVAL;
249 }
250 int
251 fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
252 {
253 	return EINVAL;
254 }
255