1 /* $NetBSD: pud.c,v 1.7 2009/01/20 18:20:48 drochner Exp $ */
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
6 * Development of this software was supported by the
7 * Research Foundation of Helsinki University of Technology
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: pud.c,v 1.7 2009/01/20 18:20:48 drochner Exp $");
34 #include <sys/param.h>
38 #include <sys/queue.h>
40 #include <dev/pud/pud_sys.h>
41 #include <dev/putter/putter_sys.h>
45 static int pud_putter_getout(void *, size_t, int, uint8_t **,
47 static void pud_putter_releaseout(void *, void *, int);
48 static int pud_putter_dispatch(void *, struct putter_hdr
*);
49 static size_t pud_putter_waitcount(void *);
50 static int pud_putter_close(void *);
52 struct putter_ops pud_putter
= {
53 .pop_getout
= pud_putter_getout
,
54 .pop_releaseout
= pud_putter_releaseout
,
55 .pop_waitcount
= pud_putter_waitcount
,
56 .pop_dispatch
= pud_putter_dispatch
,
57 .pop_close
= pud_putter_close
,
60 extern struct bdevsw pud_bdevsw
;
61 extern struct cdevsw pud_cdevsw
;
64 static LIST_HEAD(, pud_dev
) pudlist
= LIST_HEAD_INITIALIZER(pudlist
);
67 nextreq(struct pud_dev
*pd
)
71 mutex_enter(&pd
->pd_mtx
);
72 rv
= pd
->pd_nextreq
++;
73 mutex_exit(&pd
->pd_mtx
);
79 pud_putter_getout(void *this, size_t maxsize
, int nonblock
,
80 uint8_t **data
, size_t *dlen
, void **cookie
)
82 struct pud_dev
*pd
= this;
83 struct pud_touser
*putp
;
86 mutex_enter(&pd
->pd_mtx
);
88 if (TAILQ_EMPTY(&pd
->pd_waitq_req
)) {
94 error
= cv_wait_sig(&pd
->pd_waitq_req_cv
, &pd
->pd_mtx
);
101 putp
= TAILQ_FIRST(&pd
->pd_waitq_req
);
102 TAILQ_REMOVE(&pd
->pd_waitq_req
, putp
, pt_entries
);
106 mutex_exit(&pd
->pd_mtx
);
109 *data
= (uint8_t *)putp
->pt_pdr
;
110 *dlen
= putp
->pt_pdr
->pdr_pth
.pth_framelen
;
118 pud_putter_releaseout(void *this, void *cookie
, int status
)
120 struct pud_dev
*pd
= this;
121 struct pud_touser
*putp
= cookie
;
123 mutex_enter(&pd
->pd_mtx
);
124 TAILQ_INSERT_TAIL(&pd
->pd_waitq_resp
, putp
, pt_entries
);
125 mutex_exit(&pd
->pd_mtx
);
130 pud_putter_waitcount(void *this)
132 struct pud_dev
*pd
= this;
135 mutex_enter(&pd
->pd_mtx
);
136 rv
= pd
->pd_waitcount
;
137 mutex_exit(&pd
->pd_mtx
);
143 pudop_dev(struct pud_dev
*pd
, struct pud_req
*pdr
)
145 struct putter_hdr
*pth
= (void *)pdr
;
146 struct pud_touser
*putp
;
148 mutex_enter(&pd
->pd_mtx
);
149 TAILQ_FOREACH(putp
, &pd
->pd_waitq_resp
, pt_entries
)
150 if (putp
->pt_pdr
->pdr_reqid
== pdr
->pdr_reqid
)
153 mutex_exit(&pd
->pd_mtx
);
156 TAILQ_REMOVE(&pd
->pd_waitq_resp
, putp
, pt_entries
);
157 mutex_exit(&pd
->pd_mtx
);
159 if (pth
->pth_framelen
> putp
->pt_pdr
->pdr_len
) {
162 memcpy(putp
->pt_pdr
, pth
, pth
->pth_framelen
);
163 cv_signal(&putp
->pt_cv
);
169 * Register our major number. Always register char device functions,
170 * register block devices optionally.
172 * XXX: no way to configure "any major you like" currently.
175 pudconf_reg(struct pud_dev
*pd
, struct pud_conf_reg
*pcr
)
178 devmajor_t cmajor
, bmajor
;
181 if (pcr
->pm_version
!= (PUD_DEVELVERSION
| PUD_VERSION
)) {
182 printf("pud version mismatch %d vs %d\n",
183 pcr
->pm_version
& ~PUD_DEVELVERSION
, PUD_VERSION
);
184 return EINVAL
; /* XXX */
187 cmajor
= major(pcr
->pm_regdev
);
188 if (pcr
->pm_flags
& PUD_CONFFLAG_BDEV
) {
196 pcr
->pm_devname
[PUD_DEVNAME_MAX
] = '\0';
197 error
= devsw_attach(pcr
->pm_devname
, bsw
, &bmajor
,
198 &pud_cdevsw
, &cmajor
);
200 pd
->pd_dev
= pcr
->pm_regdev
;
206 pudop_conf(struct pud_dev
*pd
, struct pud_req
*pdr
)
210 switch (pdr
->pdr_reqtype
) {
212 rv
= pudconf_reg(pd
, (struct pud_conf_reg
*)pdr
);
227 pud_putter_dispatch(void *this, struct putter_hdr
*pth
)
229 struct pud_dev
*pd
= this;
230 struct pud_req
*pdr
= (void *)pth
;
233 if (pdr
->pdr_pth
.pth_framelen
< sizeof(struct pud_req
))
236 switch (pdr
->pdr_reqclass
) {
239 rv
= pudop_dev(pd
, pdr
);
242 rv
= pudop_conf(pd
, pdr
);
252 /* Device server severed the umbilical cord */
254 pud_putter_close(void *this)
256 struct pud_dev
*pd
= this;
257 struct pud_touser
*putp
;
259 mutex_enter(&pud_mtx
);
260 LIST_REMOVE(pd
, pd_entries
);
261 mutex_exit(&pud_mtx
);
263 mutex_enter(&pd
->pd_mtx
);
264 while ((putp
= TAILQ_FIRST(&pd
->pd_waitq_req
)) != NULL
) {
265 putp
->pt_pdr
->pdr_rv
= ENXIO
;
266 cv_signal(&putp
->pt_cv
);
267 TAILQ_REMOVE(&pd
->pd_waitq_req
, putp
, pt_entries
);
270 while ((putp
= TAILQ_FIRST(&pd
->pd_waitq_resp
)) != NULL
) {
271 putp
->pt_pdr
->pdr_rv
= ENXIO
;
272 cv_signal(&putp
->pt_cv
);
273 TAILQ_REMOVE(&pd
->pd_waitq_resp
, putp
, pt_entries
);
275 if (pd
->pd_waitcount
)
276 cv_wait(&pd
->pd_draincv
, &pd
->pd_mtx
);
277 KASSERT(pd
->pd_waitcount
== 0);
279 mutex_exit(&pd
->pd_mtx
);
282 devsw_detach(&pud_bdevsw
/* XXX */, &pud_cdevsw
);
284 putter_detach(pd
->pd_pi
);
286 mutex_destroy(&pd
->pd_mtx
);
287 cv_destroy(&pd
->pd_draincv
);
288 cv_destroy(&pd
->pd_waitq_req_cv
);
289 kmem_free(pd
, sizeof(struct pud_dev
));
295 pud_dev2pud(dev_t dev
)
299 mutex_enter(&pud_mtx
);
300 LIST_FOREACH(pd
, &pudlist
, pd_entries
)
301 if (major(pd
->pd_dev
) == major(dev
))
303 mutex_exit(&pud_mtx
);
308 /* Toss request to the device server and wait for result */
310 pud_request(dev_t dev
, void *data
, size_t dlen
, int class, int type
)
312 struct pud_touser put
;
313 struct pud_req
*pdr
= data
;
316 pd
= pud_dev2pud(dev
);
321 pdr
->pdr_len
= pdr
->pdr_pth
.pth_framelen
= dlen
;
322 pdr
->pdr_reqid
= nextreq(pd
);
324 pdr
->pdr_reqclass
= class;
325 pdr
->pdr_reqtype
= type
;
328 cv_init(&put
.pt_cv
, "pudresp");
330 mutex_enter(&pd
->pd_mtx
);
333 TAILQ_INSERT_TAIL(&pd
->pd_waitq_req
, &put
, pt_entries
);
334 putter_notify(pd
->pd_pi
);
335 cv_broadcast(&pd
->pd_waitq_req_cv
);
336 cv_wait(&put
.pt_cv
, &pd
->pd_mtx
);
338 if (--pd
->pd_waitcount
== 0)
339 cv_signal(&pd
->pd_draincv
);
340 mutex_exit(&pd
->pd_mtx
);
341 cv_destroy(&put
.pt_cv
);
346 /* Called from putter based on minor dev number */
348 pud_config(int fd
, int flags
, int fmt
)
352 pd
= kmem_zalloc(sizeof(struct pud_dev
), KM_SLEEP
);
353 pd
->pd_pi
= putter_attach(curlwp
->l_proc
->p_pid
, fd
, pd
, &pud_putter
);
354 if (pd
->pd_pi
== NULL
) {
355 kmem_free(pd
, sizeof(struct pud_dev
));
356 return ENOENT
; /* XXX */
360 mutex_init(&pd
->pd_mtx
, MUTEX_DEFAULT
, IPL_NONE
);
361 TAILQ_INIT(&pd
->pd_waitq_req
);
362 TAILQ_INIT(&pd
->pd_waitq_resp
);
363 cv_init(&pd
->pd_waitq_req_cv
, "pudreq");
364 cv_init(&pd
->pd_draincv
, "pudrain");
366 mutex_enter(&pud_mtx
);
367 LIST_INSERT_HEAD(&pudlist
, pd
, pd_entries
);
368 mutex_exit(&pud_mtx
);
378 if ((error
= putter_register(pud_config
, PUTTER_MINOR_PUD
)) != 0) {
379 printf("pudattach: can't register to putter: %d\n", error
);
382 mutex_init(&pud_mtx
, MUTEX_DEFAULT
, IPL_NONE
);