1107120Sjulian/*
2107120Sjulian * ng_bt3c_pccard.c
3139823Simp */
4139823Simp
5139823Simp/*-
6107120Sjulian * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7107120Sjulian * All rights reserved.
8107120Sjulian *
9107120Sjulian * Redistribution and use in source and binary forms, with or without
10107120Sjulian * modification, are permitted provided that the following conditions
11107120Sjulian * are met:
12107120Sjulian * 1. Redistributions of source code must retain the above copyright
13107120Sjulian *    notice, this list of conditions and the following disclaimer.
14107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright
15107120Sjulian *    notice, this list of conditions and the following disclaimer in the
16107120Sjulian *    documentation and/or other materials provided with the distribution.
17107120Sjulian *
18107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28107120Sjulian * SUCH DAMAGE.
29107120Sjulian *
30114878Sjulian * $Id: ng_bt3c_pccard.c,v 1.5 2003/04/01 18:15:21 max Exp $
31107120Sjulian * $FreeBSD$
32107120Sjulian *
33107120Sjulian * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
34107120Sjulian *
35107120Sjulian * Based on information obrained from: Jose Orlando Pereira <jop@di.uminho.pt>
36107120Sjulian * and disassembled w2k driver.
37107120Sjulian *
38107120Sjulian * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
39107120Sjulian *
40107120Sjulian */
41107120Sjulian
42107120Sjulian#include <sys/param.h>
43107120Sjulian#include <sys/systm.h>
44107120Sjulian
45107120Sjulian#include <sys/bus.h>
46107120Sjulian#include <machine/bus.h>
47107120Sjulian
48107120Sjulian#include <sys/conf.h>
49107120Sjulian#include <sys/endian.h>
50107120Sjulian#include <sys/interrupt.h>
51107120Sjulian#include <sys/kernel.h>
52107120Sjulian#include <sys/mbuf.h>
53107120Sjulian#include <sys/module.h>
54107120Sjulian
55107120Sjulian#include <machine/resource.h>
56107120Sjulian#include <sys/rman.h>
57107120Sjulian
58107120Sjulian#include <sys/socket.h>
59107120Sjulian#include <net/if.h>
60107120Sjulian#include <net/if_var.h>
61107120Sjulian
62107120Sjulian#include <dev/pccard/pccardreg.h>
63107120Sjulian#include <dev/pccard/pccardvar.h>
64129740Simp#include "pccarddevs.h"
65107120Sjulian
66107120Sjulian#include <netgraph/ng_message.h>
67107120Sjulian#include <netgraph/netgraph.h>
68107120Sjulian#include <netgraph/ng_parse.h>
69128688Semax#include <netgraph/bluetooth/include/ng_bluetooth.h>
70128688Semax#include <netgraph/bluetooth/include/ng_hci.h>
71128688Semax#include <netgraph/bluetooth/include/ng_bt3c.h>
72128688Semax#include <netgraph/bluetooth/drivers/bt3c/ng_bt3c_var.h>
73107120Sjulian
74107120Sjulian/* Netgraph methods */
75107120Sjulianstatic ng_constructor_t	ng_bt3c_constructor;
76107120Sjulianstatic ng_shutdown_t	ng_bt3c_shutdown;
77107120Sjulianstatic ng_newhook_t	ng_bt3c_newhook;
78107120Sjulianstatic ng_connect_t	ng_bt3c_connect;
79107120Sjulianstatic ng_disconnect_t	ng_bt3c_disconnect;
80107120Sjulianstatic ng_rcvmsg_t	ng_bt3c_rcvmsg;
81107120Sjulianstatic ng_rcvdata_t	ng_bt3c_rcvdata;
82107120Sjulian
83107120Sjulian/* PCMCIA driver methods */
84107120Sjulianstatic int	bt3c_pccard_probe	(device_t);
85107120Sjulianstatic int	bt3c_pccard_attach	(device_t);
86107120Sjulianstatic int	bt3c_pccard_detach	(device_t);
87107120Sjulian
88107120Sjulianstatic void	bt3c_intr		(void *);
89107120Sjulianstatic void	bt3c_receive		(bt3c_softc_p);
90107120Sjulian
91107120Sjulianstatic void	bt3c_swi_intr		(void *);
92107120Sjulianstatic void	bt3c_forward		(node_p, hook_p, void *, int);
93107120Sjulianstatic void	bt3c_send		(node_p, hook_p, void *, int);
94107120Sjulian
95107120Sjulianstatic void	bt3c_download_firmware	(bt3c_softc_p, char const *, int);
96107120Sjulian
97107120Sjulian#define	bt3c_set_address(sc, address) \
98107120Sjuliando { \
99160114Semax	bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_L, ((address) & 0xff)); \
100160114Semax	bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_H, (((address) >> 8) & 0xff)); \
101107120Sjulian} while (0)
102107120Sjulian
103107120Sjulian#define	bt3c_read_data(sc, data) \
104107120Sjuliando { \
105160114Semax	(data)  = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_L); \
106160114Semax	(data) |= ((bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_H) & 0xff) << 8); \
107107120Sjulian} while (0)
108107120Sjulian
109107120Sjulian#define	bt3c_write_data(sc, data) \
110107120Sjuliando { \
111160114Semax	bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_L, ((data) & 0xff)); \
112160114Semax	bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_H, (((data) >> 8) & 0xff)); \
113107120Sjulian} while (0)
114107120Sjulian
115107120Sjulian#define	bt3c_read_control(sc, data) \
116107120Sjuliando { \
117160114Semax	(data) = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_CONTROL); \
118107120Sjulian} while (0)
119107120Sjulian
120107120Sjulian#define	bt3c_write_control(sc, data) \
121107120Sjuliando { \
122160114Semax	bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_CONTROL, (data)); \
123107120Sjulian} while (0)
124107120Sjulian
125107120Sjulian#define bt3c_read(sc, address, data) \
126107120Sjuliando { \
127107120Sjulian	bt3c_set_address((sc), (address)); \
128107120Sjulian	bt3c_read_data((sc), (data)); \
129107120Sjulian} while(0)
130107120Sjulian
131107120Sjulian#define bt3c_write(sc, address, data) \
132107120Sjuliando { \
133107120Sjulian	bt3c_set_address((sc), (address)); \
134107120Sjulian	bt3c_write_data((sc), (data)); \
135107120Sjulian} while(0)
136107120Sjulian
137107120Sjulianstatic MALLOC_DEFINE(M_BT3C, "bt3c", "bt3c data structures");
138107120Sjulian
139107120Sjulian/****************************************************************************
140107120Sjulian ****************************************************************************
141107120Sjulian **                           Netgraph specific
142107120Sjulian ****************************************************************************
143107120Sjulian ****************************************************************************/
144107120Sjulian
145107120Sjulian/*
146107120Sjulian * Netgraph node type
147107120Sjulian */
148107120Sjulian
149107120Sjulian/* Queue length */
150107120Sjulianstatic const struct ng_parse_struct_field	ng_bt3c_node_qlen_type_fields[] =
151107120Sjulian{
152107120Sjulian	{ "queue", &ng_parse_int32_type, },
153107120Sjulian	{ "qlen",  &ng_parse_int32_type, },
154107120Sjulian	{ NULL, }
155107120Sjulian};
156107120Sjulianstatic const struct ng_parse_type		ng_bt3c_node_qlen_type = {
157107120Sjulian	&ng_parse_struct_type,
158107120Sjulian	&ng_bt3c_node_qlen_type_fields
159107120Sjulian};
160107120Sjulian
161107120Sjulian/* Stat info */
162107120Sjulianstatic const struct ng_parse_struct_field	ng_bt3c_node_stat_type_fields[] =
163107120Sjulian{
164107120Sjulian	{ "pckts_recv", &ng_parse_uint32_type, },
165107120Sjulian	{ "bytes_recv", &ng_parse_uint32_type, },
166107120Sjulian	{ "pckts_sent", &ng_parse_uint32_type, },
167107120Sjulian	{ "bytes_sent", &ng_parse_uint32_type, },
168107120Sjulian	{ "oerrors",    &ng_parse_uint32_type, },
169107120Sjulian	{ "ierrors",    &ng_parse_uint32_type, },
170107120Sjulian	{ NULL, }
171107120Sjulian};
172107120Sjulianstatic const struct ng_parse_type		ng_bt3c_node_stat_type = {
173107120Sjulian	&ng_parse_struct_type,
174107120Sjulian	&ng_bt3c_node_stat_type_fields
175107120Sjulian};
176107120Sjulian
177107120Sjulianstatic const struct ng_cmdlist	ng_bt3c_cmdlist[] = {
178107120Sjulian{
179107120Sjulian	NGM_BT3C_COOKIE,
180107120Sjulian	NGM_BT3C_NODE_GET_STATE,
181107120Sjulian	"get_state",
182107120Sjulian	NULL,
183107120Sjulian	&ng_parse_uint16_type
184107120Sjulian},
185107120Sjulian{
186107120Sjulian	NGM_BT3C_COOKIE,
187107120Sjulian	NGM_BT3C_NODE_SET_DEBUG,
188107120Sjulian	"set_debug",
189107120Sjulian	&ng_parse_uint16_type,
190107120Sjulian	NULL
191107120Sjulian},
192107120Sjulian{
193107120Sjulian	NGM_BT3C_COOKIE,
194107120Sjulian	NGM_BT3C_NODE_GET_DEBUG,
195107120Sjulian	"get_debug",
196107120Sjulian	NULL,
197107120Sjulian	&ng_parse_uint16_type
198107120Sjulian},
199107120Sjulian{
200107120Sjulian	NGM_BT3C_COOKIE,
201107120Sjulian	NGM_BT3C_NODE_GET_QLEN,
202107120Sjulian	"get_qlen",
203107120Sjulian	NULL,
204107120Sjulian	&ng_bt3c_node_qlen_type
205107120Sjulian},
206107120Sjulian{
207107120Sjulian	NGM_BT3C_COOKIE,
208107120Sjulian	NGM_BT3C_NODE_SET_QLEN,
209107120Sjulian	"set_qlen",
210107120Sjulian	&ng_bt3c_node_qlen_type,
211107120Sjulian	NULL
212107120Sjulian},
213107120Sjulian{
214107120Sjulian	NGM_BT3C_COOKIE,
215107120Sjulian	NGM_BT3C_NODE_GET_STAT,
216107120Sjulian	"get_stat",
217107120Sjulian	NULL,
218107120Sjulian	&ng_bt3c_node_stat_type
219107120Sjulian},
220107120Sjulian{
221107120Sjulian	NGM_BT3C_COOKIE,
222107120Sjulian	NGM_BT3C_NODE_RESET_STAT,
223107120Sjulian	"reset_stat",
224107120Sjulian	NULL,
225107120Sjulian	NULL
226107120Sjulian},
227107120Sjulian{ 0, }
228107120Sjulian};
229107120Sjulian
230107120Sjulianstatic struct ng_type	typestruct = {
231129835Sjulian	.version =	NG_ABI_VERSION,
232129835Sjulian	.name = 	NG_BT3C_NODE_TYPE,
233129835Sjulian	.constructor = 	ng_bt3c_constructor,
234129835Sjulian	.rcvmsg =	ng_bt3c_rcvmsg,
235129835Sjulian	.shutdown = 	ng_bt3c_shutdown,
236129835Sjulian	.newhook =	ng_bt3c_newhook,
237129835Sjulian	.connect =	ng_bt3c_connect,
238129835Sjulian	.rcvdata =	ng_bt3c_rcvdata,
239129835Sjulian	.disconnect =	ng_bt3c_disconnect,
240129835Sjulian        .cmdlist =	ng_bt3c_cmdlist
241107120Sjulian};
242107120Sjulian
243107120Sjulian/*
244107120Sjulian * Netgraph node constructor. Do not allow to create node of this type.
245107120Sjulian */
246107120Sjulian
247107120Sjulianstatic int
248107120Sjulianng_bt3c_constructor(node_p node)
249107120Sjulian{
250107120Sjulian	return (EINVAL);
251107120Sjulian} /* ng_bt3c_constructor */
252107120Sjulian
253107120Sjulian/*
254107120Sjulian * Netgraph node destructor. Destroy node only when device has been detached
255107120Sjulian */
256107120Sjulian
257107120Sjulianstatic int
258107120Sjulianng_bt3c_shutdown(node_p node)
259107120Sjulian{
260107120Sjulian	bt3c_softc_p	sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
261107120Sjulian
262107120Sjulian	/* Let old node go */
263107120Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
264107120Sjulian	NG_NODE_UNREF(node);
265107120Sjulian
266107120Sjulian	/* Create new fresh one if we are not going down */
267107120Sjulian	if (sc == NULL)
268107120Sjulian		goto out;
269107120Sjulian
270107120Sjulian	/* Create new Netgraph node */
271107120Sjulian	if (ng_make_node_common(&typestruct, &sc->node) != 0) {
272107120Sjulian		device_printf(sc->dev, "Could not create Netgraph node\n");
273107120Sjulian		sc->node = NULL;
274107120Sjulian		goto out;
275107120Sjulian	}
276107120Sjulian
277107120Sjulian	/* Name new Netgraph node */
278107120Sjulian	if (ng_name_node(sc->node,  device_get_nameunit(sc->dev)) != 0) {
279107120Sjulian		device_printf(sc->dev, "Could not name Netgraph node\n");
280107120Sjulian		NG_NODE_UNREF(sc->node);
281107120Sjulian		sc->node = NULL;
282107120Sjulian		goto out;
283107120Sjulian	}
284107120Sjulian
285107120Sjulian	NG_NODE_SET_PRIVATE(sc->node, sc);
286107120Sjulianout:
287107120Sjulian	return (0);
288107120Sjulian} /* ng_bt3c_shutdown */
289107120Sjulian
290107120Sjulian/*
291107120Sjulian * Create new hook. There can only be one.
292107120Sjulian */
293107120Sjulian
294107120Sjulianstatic int
295107120Sjulianng_bt3c_newhook(node_p node, hook_p hook, char const *name)
296107120Sjulian{
297107120Sjulian	bt3c_softc_p	sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
298107120Sjulian
299107120Sjulian	if (strcmp(name, NG_BT3C_HOOK) != 0)
300107120Sjulian		return (EINVAL);
301107120Sjulian
302107120Sjulian	if (sc->hook != NULL)
303107120Sjulian		return (EISCONN);
304107120Sjulian
305107120Sjulian	sc->hook = hook;
306107120Sjulian
307107120Sjulian	return (0);
308107120Sjulian} /* ng_bt3c_newhook */
309107120Sjulian
310107120Sjulian/*
311107120Sjulian * Connect hook. Say YEP, that's OK with me.
312107120Sjulian */
313107120Sjulian
314107120Sjulianstatic int
315107120Sjulianng_bt3c_connect(hook_p hook)
316107120Sjulian{
317107120Sjulian	bt3c_softc_p	sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
318107120Sjulian
319107120Sjulian	if (hook != sc->hook) {
320107120Sjulian		sc->hook = NULL;
321107120Sjulian		return (EINVAL);
322107120Sjulian	}
323107120Sjulian
324107120Sjulian	/* set the hook into queueing mode (for incoming (from wire) packets) */
325107120Sjulian	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
326107120Sjulian
327107120Sjulian	return (0);
328107120Sjulian} /* ng_bt3c_connect */
329107120Sjulian
330107120Sjulian/*
331107120Sjulian * Disconnect hook
332107120Sjulian */
333107120Sjulian
334107120Sjulianstatic int
335107120Sjulianng_bt3c_disconnect(hook_p hook)
336107120Sjulian{
337107120Sjulian	bt3c_softc_p	sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
338107120Sjulian
339107120Sjulian	/*
340107120Sjulian	 * We need to check for sc != NULL because we can be called from
341107120Sjulian	 * bt3c_pccard_detach() via ng_rmnode_self()
342107120Sjulian	 */
343107120Sjulian
344107120Sjulian	if (sc != NULL) {
345107120Sjulian		if (hook != sc->hook)
346107120Sjulian			return (EINVAL);
347107120Sjulian
348107120Sjulian		IF_DRAIN(&sc->inq);
349107120Sjulian		IF_DRAIN(&sc->outq);
350107120Sjulian
351107120Sjulian		sc->hook = NULL;
352107120Sjulian	}
353107120Sjulian
354107120Sjulian	return (0);
355107120Sjulian} /* ng_bt3c_disconnect */
356107120Sjulian
357107120Sjulian/*
358107120Sjulian * Process control message
359107120Sjulian */
360107120Sjulian
361107120Sjulianstatic int
362107120Sjulianng_bt3c_rcvmsg(node_p node, item_p item, hook_p lasthook)
363107120Sjulian{
364107120Sjulian	bt3c_softc_p	 sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
365107120Sjulian	struct ng_mesg	*msg = NULL, *rsp = NULL;
366107120Sjulian	int		 error = 0;
367107120Sjulian
368107120Sjulian	if (sc == NULL) {
369107120Sjulian		NG_FREE_ITEM(item);
370107120Sjulian		return (EHOSTDOWN);
371107120Sjulian	}
372107120Sjulian
373107120Sjulian	NGI_GET_MSG(item, msg);
374107120Sjulian
375107120Sjulian	switch (msg->header.typecookie) {
376107120Sjulian	case NGM_GENERIC_COOKIE:
377107120Sjulian		switch (msg->header.cmd) {
378107120Sjulian		case NGM_TEXT_STATUS:
379107120Sjulian			NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT);
380107120Sjulian			if (rsp == NULL)
381107120Sjulian				error = ENOMEM;
382107120Sjulian			else
383107120Sjulian				snprintf(rsp->data, NG_TEXTRESPONSE,
384107120Sjulian					"Hook: %s\n" \
385107120Sjulian					"Flags: %#x\n" \
386107120Sjulian					"Debug: %d\n"  \
387107120Sjulian					"State: %d\n"  \
388107120Sjulian					"IncmQ: [len:%d,max:%d]\n" \
389107120Sjulian					"OutgQ: [len:%d,max:%d]\n",
390107120Sjulian					(sc->hook != NULL)? NG_BT3C_HOOK : "",
391107120Sjulian					sc->flags,
392107120Sjulian					sc->debug,
393107120Sjulian					sc->state,
394107120Sjulian					_IF_QLEN(&sc->inq), /* XXX */
395107120Sjulian					sc->inq.ifq_maxlen, /* XXX */
396107120Sjulian					_IF_QLEN(&sc->outq), /* XXX */
397107120Sjulian					sc->outq.ifq_maxlen /* XXX */
398107120Sjulian					);
399107120Sjulian			break;
400107120Sjulian
401107120Sjulian		default:
402107120Sjulian			error = EINVAL;
403107120Sjulian			break;
404107120Sjulian		}
405107120Sjulian		break;
406107120Sjulian
407107120Sjulian	case NGM_BT3C_COOKIE:
408107120Sjulian		switch (msg->header.cmd) {
409107120Sjulian		case NGM_BT3C_NODE_GET_STATE:
410107120Sjulian			NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_state_ep),
411107120Sjulian				M_NOWAIT);
412107120Sjulian			if (rsp == NULL)
413107120Sjulian				error = ENOMEM;
414107120Sjulian			else
415107120Sjulian				*((ng_bt3c_node_state_ep *)(rsp->data)) =
416107120Sjulian					sc->state;
417107120Sjulian			break;
418107120Sjulian
419107120Sjulian		case NGM_BT3C_NODE_SET_DEBUG:
420107120Sjulian			if (msg->header.arglen != sizeof(ng_bt3c_node_debug_ep))
421107120Sjulian				error = EMSGSIZE;
422107120Sjulian			else
423107120Sjulian				sc->debug =
424107120Sjulian					*((ng_bt3c_node_debug_ep *)(msg->data));
425107120Sjulian			break;
426107120Sjulian
427107120Sjulian		case NGM_BT3C_NODE_GET_DEBUG:
428107120Sjulian			NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_debug_ep),
429107120Sjulian				M_NOWAIT);
430107120Sjulian			if (rsp == NULL)
431107120Sjulian				error = ENOMEM;
432107120Sjulian			else
433107120Sjulian				*((ng_bt3c_node_debug_ep *)(rsp->data)) =
434107120Sjulian					sc->debug;
435107120Sjulian			break;
436107120Sjulian
437107120Sjulian		case NGM_BT3C_NODE_GET_QLEN:
438107120Sjulian			NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_qlen_ep),
439107120Sjulian				M_NOWAIT);
440107120Sjulian			if (rsp == NULL) {
441107120Sjulian				error = ENOMEM;
442107120Sjulian				break;
443107120Sjulian			}
444107120Sjulian
445107120Sjulian			switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) {
446107120Sjulian			case NGM_BT3C_NODE_IN_QUEUE:
447107120Sjulian				((ng_bt3c_node_qlen_ep *)(rsp->data))->queue =
448107120Sjulian					NGM_BT3C_NODE_IN_QUEUE;
449107120Sjulian				((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen =
450107120Sjulian					sc->inq.ifq_maxlen;
451107120Sjulian				break;
452107120Sjulian
453107120Sjulian			case NGM_BT3C_NODE_OUT_QUEUE:
454107120Sjulian				((ng_bt3c_node_qlen_ep *)(rsp->data))->queue =
455107120Sjulian					NGM_BT3C_NODE_OUT_QUEUE;
456107120Sjulian				((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen =
457107120Sjulian					sc->outq.ifq_maxlen;
458107120Sjulian				break;
459107120Sjulian
460107120Sjulian			default:
461107120Sjulian				NG_FREE_MSG(rsp);
462107120Sjulian				error = EINVAL;
463107120Sjulian				break;
464107120Sjulian			}
465107120Sjulian			break;
466107120Sjulian
467107120Sjulian		case NGM_BT3C_NODE_SET_QLEN:
468107120Sjulian			if (msg->header.arglen != sizeof(ng_bt3c_node_qlen_ep)){
469107120Sjulian				error = EMSGSIZE;
470107120Sjulian				break;
471107120Sjulian			}
472107120Sjulian
473107120Sjulian			if (((ng_bt3c_node_qlen_ep *)(msg->data))->qlen <= 0) {
474107120Sjulian				error = EINVAL;
475107120Sjulian				break;
476107120Sjulian			}
477107120Sjulian
478107120Sjulian			switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) {
479107120Sjulian			case NGM_BT3C_NODE_IN_QUEUE:
480107120Sjulian				sc->inq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *)
481107120Sjulian					(msg->data))->qlen; /* XXX */
482107120Sjulian				break;
483107120Sjulian
484107120Sjulian			case NGM_BT3C_NODE_OUT_QUEUE:
485107120Sjulian				sc->outq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *)
486107120Sjulian					(msg->data))->qlen; /* XXX */
487107120Sjulian				break;
488107120Sjulian
489107120Sjulian			default:
490107120Sjulian				error = EINVAL;
491107120Sjulian				break;
492107120Sjulian			}
493107120Sjulian			break;
494107120Sjulian
495107120Sjulian		case NGM_BT3C_NODE_GET_STAT:
496107120Sjulian			NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_stat_ep),
497107120Sjulian				M_NOWAIT);
498107120Sjulian			if (rsp == NULL)
499107120Sjulian				error = ENOMEM;
500107120Sjulian			else
501107120Sjulian				bcopy(&sc->stat, rsp->data,
502107120Sjulian					sizeof(ng_bt3c_node_stat_ep));
503107120Sjulian			break;
504107120Sjulian
505107120Sjulian		case NGM_BT3C_NODE_RESET_STAT:
506107120Sjulian			NG_BT3C_STAT_RESET(sc->stat);
507107120Sjulian			break;
508107120Sjulian
509107120Sjulian		case NGM_BT3C_NODE_DOWNLOAD_FIRMWARE:
510107120Sjulian			if (msg->header.arglen <
511107120Sjulian					sizeof(ng_bt3c_firmware_block_ep))
512107120Sjulian				error = EMSGSIZE;
513107120Sjulian			else
514107120Sjulian				bt3c_download_firmware(sc, msg->data,
515107120Sjulian							msg->header.arglen);
516107120Sjulian			break;
517107120Sjulian
518107120Sjulian		default:
519107120Sjulian			error = EINVAL;
520107120Sjulian			break;
521107120Sjulian		}
522107120Sjulian		break;
523107120Sjulian
524107120Sjulian	default:
525107120Sjulian		error = EINVAL;
526107120Sjulian		break;
527107120Sjulian	}
528107120Sjulian
529107120Sjulian	NG_RESPOND_MSG(error, node, item, rsp);
530107120Sjulian	NG_FREE_MSG(msg);
531107120Sjulian
532107120Sjulian	return (error);
533107120Sjulian} /* ng_bt3c_rcvmsg */
534107120Sjulian
535107120Sjulian/*
536107120Sjulian * Process data
537107120Sjulian */
538107120Sjulian
539107120Sjulianstatic int
540107120Sjulianng_bt3c_rcvdata(hook_p hook, item_p item)
541107120Sjulian{
542107120Sjulian	bt3c_softc_p	 sc = (bt3c_softc_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
543107120Sjulian	struct mbuf	*m = NULL;
544107120Sjulian	int		 error = 0;
545107120Sjulian
546107120Sjulian	if (sc == NULL) {
547107120Sjulian		error = EHOSTDOWN;
548107120Sjulian		goto out;
549107120Sjulian	}
550107120Sjulian
551107120Sjulian	if (hook != sc->hook) {
552107120Sjulian		error = EINVAL;
553107120Sjulian		goto out;
554107120Sjulian	}
555107120Sjulian
556107120Sjulian	NGI_GET_M(item, m);
557107120Sjulian
558107120Sjulian	IF_LOCK(&sc->outq);
559107120Sjulian	if (_IF_QFULL(&sc->outq)) {
560107120Sjulian		NG_BT3C_ERR(sc->dev,
561107120Sjulian"Outgoing queue is full. Dropping mbuf, len=%d\n", m->m_pkthdr.len);
562107120Sjulian
563107120Sjulian		_IF_DROP(&sc->outq);
564107120Sjulian		NG_BT3C_STAT_OERROR(sc->stat);
565107120Sjulian
566107120Sjulian		NG_FREE_M(m);
567107120Sjulian	} else
568107120Sjulian		_IF_ENQUEUE(&sc->outq, m);
569107120Sjulian	IF_UNLOCK(&sc->outq);
570107120Sjulian
571107120Sjulian	error = ng_send_fn(sc->node, NULL, bt3c_send, NULL, 0 /* new send */);
572107120Sjulianout:
573107120Sjulian        NG_FREE_ITEM(item);
574107120Sjulian
575107120Sjulian	return (error);
576107120Sjulian} /* ng_bt3c_rcvdata */
577107120Sjulian
578107120Sjulian/****************************************************************************
579107120Sjulian ****************************************************************************
580107120Sjulian **                         PCMCIA driver specific
581107120Sjulian ****************************************************************************
582107120Sjulian ****************************************************************************/
583107120Sjulian
584107120Sjulian/*
585150456Simp * PC Card (PCMCIA) probe routine
586107120Sjulian */
587107120Sjulian
588107120Sjulianstatic int
589150456Simpbt3c_pccard_probe(device_t dev)
590107120Sjulian{
591107120Sjulian	static struct pccard_product const	bt3c_pccard_products[] = {
592147580Simp		PCMCIA_CARD(3COM, 3CRWB609),
593107120Sjulian		{ NULL, }
594107120Sjulian	};
595107120Sjulian
596107120Sjulian	struct pccard_product const	*pp = NULL;
597107120Sjulian
598107120Sjulian	pp = pccard_product_lookup(dev, bt3c_pccard_products,
599107120Sjulian			sizeof(bt3c_pccard_products[0]), NULL);
600107120Sjulian	if (pp == NULL)
601137896Semax		return (ENXIO);
602107120Sjulian
603107120Sjulian	device_set_desc(dev, pp->pp_name);
604107120Sjulian
605107120Sjulian	return (0);
606150482Semax} /* bt3c_pccard_probe */
607107120Sjulian
608107120Sjulian/*
609150456Simp * PC Card (PCMCIA) attach routine
610107120Sjulian */
611107120Sjulian
612107120Sjulianstatic int
613107120Sjulianbt3c_pccard_attach(device_t dev)
614107120Sjulian{
615151726Semax	bt3c_softc_p	sc = (bt3c_softc_p) device_get_softc(dev);
616107120Sjulian
617107120Sjulian	/* Allocate I/O ports */
618107120Sjulian	sc->iobase_rid = 0;
619107120Sjulian	sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iobase_rid,
620107120Sjulian			0, ~0, 8, RF_ACTIVE);
621107120Sjulian	if (sc->iobase == NULL) {
622107120Sjulian		device_printf(dev, "Could not allocate I/O ports\n");
623107120Sjulian		goto bad;
624107120Sjulian	}
625160114Semax	sc->iot = rman_get_bustag(sc->iobase);
626160114Semax	sc->ioh = rman_get_bushandle(sc->iobase);
627107120Sjulian
628107120Sjulian	/* Allocate IRQ */
629107120Sjulian	sc->irq_rid = 0;
630127135Snjl	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
631127135Snjl			RF_ACTIVE);
632107120Sjulian	if (sc->irq == NULL) {
633107120Sjulian		device_printf(dev, "Could not allocate IRQ\n");
634107120Sjulian		goto bad;
635107120Sjulian	}
636107120Sjulian
637107120Sjulian	sc->irq_cookie = NULL;
638166901Spiso	if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, NULL, bt3c_intr, sc,
639107120Sjulian			&sc->irq_cookie) != 0) {
640107120Sjulian		device_printf(dev, "Could not setup ISR\n");
641107120Sjulian		goto bad;
642107120Sjulian	}
643107120Sjulian
644107120Sjulian	/* Attach handler to TTY SWI thread */
645107120Sjulian	sc->ith = NULL;
646151689Sru	if (swi_add(&tty_intr_event, device_get_nameunit(dev),
647107120Sjulian			bt3c_swi_intr, sc, SWI_TTY, 0, &sc->ith) < 0) {
648107120Sjulian		device_printf(dev, "Could not setup SWI ISR\n");
649107120Sjulian		goto bad;
650107120Sjulian	}
651107120Sjulian
652107120Sjulian	/* Create Netgraph node */
653107120Sjulian	if (ng_make_node_common(&typestruct, &sc->node) != 0) {
654107120Sjulian		device_printf(dev, "Could not create Netgraph node\n");
655107120Sjulian		sc->node = NULL;
656107120Sjulian		goto bad;
657107120Sjulian	}
658107120Sjulian
659107120Sjulian	/* Name Netgraph node */
660107120Sjulian	if (ng_name_node(sc->node, device_get_nameunit(dev)) != 0) {
661107120Sjulian		device_printf(dev, "Could not name Netgraph node\n");
662107120Sjulian		NG_NODE_UNREF(sc->node);
663107120Sjulian		sc->node = NULL;
664107120Sjulian		goto bad;
665107120Sjulian	}
666107120Sjulian
667107120Sjulian	sc->dev = dev;
668107120Sjulian	sc->debug = NG_BT3C_WARN_LEVEL;
669107120Sjulian
670107120Sjulian	sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = BT3C_DEFAULTQLEN;
671107120Sjulian	mtx_init(&sc->inq.ifq_mtx, "BT3C inq", NULL, MTX_DEF);
672107120Sjulian	mtx_init(&sc->outq.ifq_mtx, "BT3C outq", NULL, MTX_DEF);
673107120Sjulian
674107120Sjulian	sc->state = NG_BT3C_W4_PKT_IND;
675107120Sjulian	sc->want = 1;
676107120Sjulian
677107120Sjulian	NG_NODE_SET_PRIVATE(sc->node, sc);
678107120Sjulian
679107120Sjulian	return (0);
680107120Sjulianbad:
681107120Sjulian	if (sc->ith != NULL) {
682151700Sjhb		swi_remove(sc->ith);
683107120Sjulian		sc->ith = NULL;
684107120Sjulian	}
685107120Sjulian
686107120Sjulian	if (sc->irq != NULL) {
687107120Sjulian		if (sc->irq_cookie != NULL)
688107120Sjulian			bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
689107120Sjulian
690107120Sjulian		bus_release_resource(dev, SYS_RES_IRQ,
691107120Sjulian			sc->irq_rid, sc->irq);
692107120Sjulian
693107120Sjulian		sc->irq = NULL;
694107120Sjulian		sc->irq_rid = 0;
695107120Sjulian	}
696107120Sjulian
697107120Sjulian	if (sc->iobase != NULL) {
698107120Sjulian		bus_release_resource(dev, SYS_RES_IOPORT,
699107120Sjulian			sc->iobase_rid, sc->iobase);
700107120Sjulian
701107120Sjulian		sc->iobase = NULL;
702107120Sjulian		sc->iobase_rid = 0;
703107120Sjulian	}
704107120Sjulian
705107120Sjulian	return (ENXIO);
706107120Sjulian} /* bt3c_pccacd_attach */
707107120Sjulian
708107120Sjulian/*
709150456Simp * PC Card (PCMCIA) detach routine
710107120Sjulian */
711107120Sjulian
712107120Sjulianstatic int
713107120Sjulianbt3c_pccard_detach(device_t dev)
714107120Sjulian{
715107120Sjulian	bt3c_softc_p	sc = (bt3c_softc_p) device_get_softc(dev);
716107120Sjulian
717107120Sjulian	if (sc == NULL)
718107120Sjulian		return (0);
719107120Sjulian
720151700Sjhb	swi_remove(sc->ith);
721107120Sjulian	sc->ith = NULL;
722107120Sjulian
723107120Sjulian	bus_teardown_intr(dev, sc->irq, sc->irq_cookie);
724107120Sjulian	bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
725107120Sjulian	sc->irq_cookie = NULL;
726107120Sjulian	sc->irq = NULL;
727107120Sjulian	sc->irq_rid = 0;
728107120Sjulian
729107120Sjulian	bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase);
730107120Sjulian	sc->iobase = NULL;
731107120Sjulian	sc->iobase_rid = 0;
732107120Sjulian
733107120Sjulian	if (sc->node != NULL) {
734107120Sjulian		NG_NODE_SET_PRIVATE(sc->node, NULL);
735107120Sjulian		ng_rmnode_self(sc->node);
736107120Sjulian		sc->node = NULL;
737107120Sjulian	}
738107120Sjulian
739107120Sjulian	NG_FREE_M(sc->m);
740107120Sjulian	IF_DRAIN(&sc->inq);
741107120Sjulian	IF_DRAIN(&sc->outq);
742107120Sjulian
743107120Sjulian	mtx_destroy(&sc->inq.ifq_mtx);
744107120Sjulian	mtx_destroy(&sc->outq.ifq_mtx);
745107120Sjulian
746107120Sjulian	return (0);
747107120Sjulian} /* bt3c_pccacd_detach */
748107120Sjulian
749107120Sjulian/*
750107120Sjulian * Interrupt service routine's
751107120Sjulian */
752107120Sjulian
753107120Sjulianstatic void
754107120Sjulianbt3c_intr(void *context)
755107120Sjulian{
756107120Sjulian	bt3c_softc_p	sc = (bt3c_softc_p) context;
757107120Sjulian	u_int16_t	control, status;
758107120Sjulian
759107120Sjulian	if (sc == NULL || sc->ith == NULL) {
760107120Sjulian		printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE);
761107120Sjulian		return;
762107120Sjulian	}
763107120Sjulian
764107120Sjulian	bt3c_read_control(sc, control);
765107120Sjulian	if ((control & 0x80) == 0)
766107120Sjulian		return;
767107120Sjulian
768107120Sjulian	bt3c_read(sc, 0x7001, status);
769107120Sjulian	NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status);
770107120Sjulian
771107120Sjulian	if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) {
772107120Sjulian		NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status);
773107120Sjulian		return;
774107120Sjulian	}
775107120Sjulian
776107120Sjulian	/* Receive complete */
777107120Sjulian	if (status & 0x0001)
778107120Sjulian		bt3c_receive(sc);
779107120Sjulian
780107120Sjulian	/* Record status and schedule SWI */
781107120Sjulian	sc->status |= status;
782107120Sjulian	swi_sched(sc->ith, 0);
783107120Sjulian
784107120Sjulian	/* Complete interrupt */
785107120Sjulian	bt3c_write(sc, 0x7001, 0x0000);
786107120Sjulian	bt3c_write_control(sc, control);
787107120Sjulian} /* bt3c_intr */
788107120Sjulian
789107120Sjulian/*
790107120Sjulian * Receive data
791107120Sjulian */
792107120Sjulian
793107120Sjulianstatic void
794107120Sjulianbt3c_receive(bt3c_softc_p sc)
795107120Sjulian{
796107120Sjulian	u_int16_t	i, count, c;
797107120Sjulian
798107120Sjulian	/* Receive data from the card */
799107120Sjulian	bt3c_read(sc, 0x7006, count);
800107120Sjulian	NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count);
801107120Sjulian
802107120Sjulian	bt3c_set_address(sc, 0x7480);
803107120Sjulian
804107120Sjulian	for (i = 0; i < count; i++) {
805107120Sjulian		/* Allocate new mbuf if needed */
806107120Sjulian		if (sc->m == NULL) {
807107120Sjulian			sc->state = NG_BT3C_W4_PKT_IND;
808107120Sjulian			sc->want = 1;
809107120Sjulian
810243882Sglebius			MGETHDR(sc->m, M_NOWAIT, MT_DATA);
811107120Sjulian			if (sc->m == NULL) {
812107120Sjulian				NG_BT3C_ERR(sc->dev, "Could not get mbuf\n");
813107120Sjulian				NG_BT3C_STAT_IERROR(sc->stat);
814107120Sjulian
815107120Sjulian				break; /* XXX lost of sync */
816107120Sjulian			}
817107120Sjulian
818243882Sglebius			MCLGET(sc->m, M_NOWAIT);
819114878Sjulian			if (!(sc->m->m_flags & M_EXT)) {
820114878Sjulian				NG_FREE_M(sc->m);
821114878Sjulian
822114878Sjulian				NG_BT3C_ERR(sc->dev, "Could not get cluster\n");
823114878Sjulian				NG_BT3C_STAT_IERROR(sc->stat);
824114878Sjulian
825114878Sjulian				break; /* XXX lost of sync */
826114878Sjulian			}
827114878Sjulian
828107120Sjulian			sc->m->m_len = sc->m->m_pkthdr.len = 0;
829107120Sjulian		}
830107120Sjulian
831107120Sjulian		/* Read and append character to mbuf */
832107120Sjulian		bt3c_read_data(sc, c);
833114878Sjulian		if (sc->m->m_pkthdr.len >= MCLBYTES) {
834114878Sjulian			NG_BT3C_ERR(sc->dev, "Oversized frame\n");
835114878Sjulian
836107120Sjulian			NG_FREE_M(sc->m);
837107120Sjulian			sc->state = NG_BT3C_W4_PKT_IND;
838107120Sjulian			sc->want = 1;
839107120Sjulian
840107120Sjulian			break; /* XXX lost of sync */
841107120Sjulian		}
842107120Sjulian
843114878Sjulian		mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c;
844114878Sjulian		sc->m->m_pkthdr.len ++;
845114878Sjulian
846107120Sjulian		NG_BT3C_INFO(sc->dev,
847107120Sjulian"Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len);
848107120Sjulian
849107120Sjulian		if (sc->m->m_pkthdr.len < sc->want)
850107120Sjulian			continue; /* wait for more */
851107120Sjulian
852107120Sjulian		switch (sc->state) {
853107120Sjulian		/* Got packet indicator */
854107120Sjulian		case NG_BT3C_W4_PKT_IND:
855107120Sjulian			NG_BT3C_INFO(sc->dev,
856107120Sjulian"Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *));
857107120Sjulian
858107120Sjulian			sc->state = NG_BT3C_W4_PKT_HDR;
859107120Sjulian
860107120Sjulian			/*
861107120Sjulian			 * Since packet indicator included in the packet
862107120Sjulian			 * header just set sc->want to sizeof(packet header).
863107120Sjulian			 */
864107120Sjulian
865107120Sjulian			switch (*mtod(sc->m, u_int8_t *)) {
866107120Sjulian			case NG_HCI_ACL_DATA_PKT:
867107120Sjulian				sc->want = sizeof(ng_hci_acldata_pkt_t);
868107120Sjulian				break;
869107120Sjulian
870107120Sjulian			case NG_HCI_SCO_DATA_PKT:
871107120Sjulian				sc->want = sizeof(ng_hci_scodata_pkt_t);
872107120Sjulian				break;
873107120Sjulian
874107120Sjulian			case NG_HCI_EVENT_PKT:
875107120Sjulian				sc->want = sizeof(ng_hci_event_pkt_t);
876107120Sjulian				break;
877107120Sjulian
878107120Sjulian			default:
879107120Sjulian       	                	NG_BT3C_ERR(sc->dev,
880107120Sjulian"Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *));
881107120Sjulian
882107120Sjulian				NG_BT3C_STAT_IERROR(sc->stat);
883107120Sjulian
884107120Sjulian				NG_FREE_M(sc->m);
885107120Sjulian				sc->state = NG_BT3C_W4_PKT_IND;
886107120Sjulian				sc->want = 1;
887107120Sjulian				break;
888107120Sjulian			}
889107120Sjulian			break;
890107120Sjulian
891107120Sjulian		/* Got packet header */
892107120Sjulian		case NG_BT3C_W4_PKT_HDR:
893107120Sjulian			sc->state = NG_BT3C_W4_PKT_DATA;
894107120Sjulian
895107120Sjulian			switch (*mtod(sc->m, u_int8_t *)) {
896107120Sjulian			case NG_HCI_ACL_DATA_PKT:
897107120Sjulian				c = le16toh(mtod(sc->m,
898107120Sjulian					ng_hci_acldata_pkt_t *)->length);
899107120Sjulian				break;
900107120Sjulian
901107120Sjulian			case NG_HCI_SCO_DATA_PKT:
902107120Sjulian				c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length;
903107120Sjulian				break;
904107120Sjulian
905107120Sjulian			case NG_HCI_EVENT_PKT:
906107120Sjulian				c = mtod(sc->m, ng_hci_event_pkt_t *)->length;
907107120Sjulian				break;
908107120Sjulian
909107120Sjulian			default:
910107120Sjulian				KASSERT(0,
911107120Sjulian("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *)));
912107120Sjulian				break;
913107120Sjulian       	        	 }
914107120Sjulian
915107120Sjulian			NG_BT3C_INFO(sc->dev,
916107120Sjulian"Got packet header, packet type=%#x, got so far %d, payload size=%d\n",
917107120Sjulian				*mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len,
918107120Sjulian				c);
919107120Sjulian
920107120Sjulian			if (c > 0) {
921107120Sjulian				sc->want += c;
922107120Sjulian				break;
923107120Sjulian			}
924107120Sjulian
925107120Sjulian			/* else FALLTHROUGH and deliver frame */
926107120Sjulian			/* XXX is this true? should we deliver empty frame? */
927107120Sjulian
928107120Sjulian		/* Got packet data */
929107120Sjulian		case NG_BT3C_W4_PKT_DATA:
930107120Sjulian			NG_BT3C_INFO(sc->dev,
931107120Sjulian"Got full packet, packet type=%#x, packet size=%d\n",
932107120Sjulian				*mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len);
933107120Sjulian
934107120Sjulian			NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len);
935107120Sjulian			NG_BT3C_STAT_PCKTS_RECV(sc->stat);
936107120Sjulian
937107120Sjulian			IF_LOCK(&sc->inq);
938107120Sjulian			if (_IF_QFULL(&sc->inq)) {
939107120Sjulian				NG_BT3C_ERR(sc->dev,
940107120Sjulian"Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len);
941107120Sjulian
942107120Sjulian				_IF_DROP(&sc->inq);
943107120Sjulian				NG_BT3C_STAT_IERROR(sc->stat);
944107120Sjulian
945107120Sjulian				NG_FREE_M(sc->m);
946107120Sjulian			} else {
947107120Sjulian				_IF_ENQUEUE(&sc->inq, sc->m);
948107120Sjulian				sc->m = NULL;
949107120Sjulian			}
950107120Sjulian			IF_UNLOCK(&sc->inq);
951107120Sjulian
952107120Sjulian			sc->state = NG_BT3C_W4_PKT_IND;
953107120Sjulian			sc->want = 1;
954107120Sjulian			break;
955107120Sjulian
956107120Sjulian		default:
957107120Sjulian			KASSERT(0,
958107120Sjulian("Invalid node state=%d", sc->state));
959107120Sjulian			break;
960107120Sjulian		}
961107120Sjulian	}
962107120Sjulian
963107120Sjulian	bt3c_write(sc, 0x7006, 0x0000);
964107120Sjulian} /* bt3c_receive */
965107120Sjulian
966107120Sjulian/*
967107120Sjulian * SWI interrupt handler
968107120Sjulian * Netgraph part is handled via ng_send_fn() to avoid race with hook
969107120Sjulian * connection/disconnection
970107120Sjulian */
971107120Sjulian
972107120Sjulianstatic void
973107120Sjulianbt3c_swi_intr(void *context)
974107120Sjulian{
975107120Sjulian	bt3c_softc_p	sc = (bt3c_softc_p) context;
976107120Sjulian	u_int16_t	data;
977107120Sjulian
978107120Sjulian	/* Receive complete */
979107120Sjulian	if (sc->status & 0x0001) {
980107120Sjulian		sc->status &= ~0x0001; /* XXX is it safe? */
981107120Sjulian
982107120Sjulian		if (ng_send_fn(sc->node, NULL, &bt3c_forward, NULL, 0) != 0)
983107120Sjulian			NG_BT3C_ALERT(sc->dev, "Could not forward frames!\n");
984107120Sjulian	}
985107120Sjulian
986107120Sjulian	/* Send complete */
987107120Sjulian	if (sc->status & 0x0002) {
988107120Sjulian		sc->status &= ~0x0002; /* XXX is it safe */
989107120Sjulian
990107120Sjulian		if (ng_send_fn(sc->node, NULL, &bt3c_send, NULL, 1) != 0)
991107120Sjulian			NG_BT3C_ALERT(sc->dev, "Could not send frames!\n");
992107120Sjulian	}
993107120Sjulian
994107120Sjulian	/* Antenna position */
995107120Sjulian	if (sc->status & 0x0020) {
996107120Sjulian		sc->status &= ~0x0020; /* XXX is it safe */
997107120Sjulian
998107120Sjulian		bt3c_read(sc, 0x7002, data);
999107120Sjulian		data &= 0x10;
1000107120Sjulian
1001107120Sjulian		if (data)
1002107120Sjulian			sc->flags |= BT3C_ANTENNA_OUT;
1003107120Sjulian		else
1004107120Sjulian			sc->flags &= ~BT3C_ANTENNA_OUT;
1005107120Sjulian
1006107120Sjulian		NG_BT3C_INFO(sc->dev, "Antenna %s\n", data? "OUT" : "IN");
1007107120Sjulian	}
1008107120Sjulian} /* bt3c_swi_intr */
1009107120Sjulian
1010107120Sjulian/*
1011107120Sjulian * Send all incoming frames to the upper layer
1012107120Sjulian */
1013107120Sjulian
1014107120Sjulianstatic void
1015107120Sjulianbt3c_forward(node_p node, hook_p hook, void *arg1, int arg2)
1016107120Sjulian{
1017107120Sjulian	bt3c_softc_p	 sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1018107120Sjulian	struct mbuf	*m = NULL;
1019107120Sjulian	int		 error;
1020107120Sjulian
1021107120Sjulian	if (sc == NULL)
1022107120Sjulian		return;
1023107120Sjulian
1024107120Sjulian	if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) {
1025107120Sjulian		for (;;) {
1026107120Sjulian			IF_DEQUEUE(&sc->inq, m);
1027107120Sjulian			if (m == NULL)
1028107120Sjulian				break;
1029107120Sjulian
1030107120Sjulian			NG_SEND_DATA_ONLY(error, sc->hook, m);
1031107120Sjulian			if (error != 0)
1032107120Sjulian				NG_BT3C_STAT_IERROR(sc->stat);
1033107120Sjulian		}
1034107120Sjulian	} else {
1035107120Sjulian		IF_LOCK(&sc->inq);
1036107120Sjulian		for (;;) {
1037107120Sjulian			_IF_DEQUEUE(&sc->inq, m);
1038107120Sjulian			if (m == NULL)
1039107120Sjulian				break;
1040107120Sjulian
1041107120Sjulian			NG_BT3C_STAT_IERROR(sc->stat);
1042107120Sjulian			NG_FREE_M(m);
1043107120Sjulian		}
1044107120Sjulian		IF_UNLOCK(&sc->inq);
1045107120Sjulian	}
1046107120Sjulian} /* bt3c_forward */
1047107120Sjulian
1048107120Sjulian/*
1049107120Sjulian * Send more data to the device. Must be called when node is locked
1050107120Sjulian */
1051107120Sjulian
1052107120Sjulianstatic void
1053107120Sjulianbt3c_send(node_p node, hook_p hook, void *arg, int completed)
1054107120Sjulian{
1055107120Sjulian	bt3c_softc_p	 sc = (bt3c_softc_p) NG_NODE_PRIVATE(node);
1056107120Sjulian	struct mbuf	*m = NULL;
1057107120Sjulian	int		 i, wrote, len;
1058107120Sjulian
1059107120Sjulian	if (sc == NULL)
1060107120Sjulian		return;
1061107120Sjulian
1062107120Sjulian	if (completed)
1063107120Sjulian		sc->flags &= ~BT3C_XMIT;
1064107120Sjulian
1065107120Sjulian	if (sc->flags & BT3C_XMIT)
1066107120Sjulian		return;
1067107120Sjulian
1068107120Sjulian	bt3c_set_address(sc, 0x7080);
1069107120Sjulian
1070107120Sjulian	for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) {
1071107120Sjulian		IF_DEQUEUE(&sc->outq, m);
1072107120Sjulian		if (m == NULL)
1073107120Sjulian			break;
1074107120Sjulian
1075107120Sjulian		while (m != NULL) {
1076107120Sjulian			len = min((BT3C_FIFO_SIZE - wrote), m->m_len);
1077107120Sjulian
1078144724Semax			for (i = 0; i < len; i++)
1079107120Sjulian				bt3c_write_data(sc, m->m_data[i]);
1080107120Sjulian
1081107120Sjulian			wrote += len;
1082107120Sjulian			m->m_data += len;
1083107120Sjulian			m->m_len -= len;
1084107120Sjulian
1085107120Sjulian			if (m->m_len > 0)
1086107120Sjulian				break;
1087107120Sjulian
1088107120Sjulian			m = m_free(m);
1089107120Sjulian		}
1090107120Sjulian
1091107120Sjulian		if (m != NULL) {
1092107120Sjulian			IF_PREPEND(&sc->outq, m);
1093107120Sjulian			break;
1094107120Sjulian		}
1095107120Sjulian
1096107120Sjulian		NG_BT3C_STAT_PCKTS_SENT(sc->stat);
1097107120Sjulian	}
1098107120Sjulian
1099107120Sjulian	if (wrote > 0) {
1100107120Sjulian		NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote);
1101107120Sjulian		NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote);
1102107120Sjulian
1103107120Sjulian		bt3c_write(sc, 0x7005, wrote);
1104107120Sjulian		sc->flags |= BT3C_XMIT;
1105107120Sjulian	}
1106107120Sjulian} /* bt3c_send */
1107107120Sjulian
1108107120Sjulian/*
1109107120Sjulian * Download chip firmware
1110107120Sjulian */
1111107120Sjulian
1112107120Sjulianstatic void
1113107120Sjulianbt3c_download_firmware(bt3c_softc_p sc, char const *firmware, int firmware_size)
1114107120Sjulian{
1115107120Sjulian	ng_bt3c_firmware_block_ep const	*block = NULL;
1116107120Sjulian	u_int16_t const			*data = NULL;
1117107120Sjulian	int				 i, size;
1118107120Sjulian	u_int8_t			 c;
1119107120Sjulian
1120107120Sjulian	/* Reset */
1121107120Sjulian	device_printf(sc->dev, "Reseting the card...\n");
1122107120Sjulian	bt3c_write(sc, 0x8040, 0x0404);
1123107120Sjulian	bt3c_write(sc, 0x8040, 0x0400);
1124107120Sjulian	DELAY(1);
1125107120Sjulian
1126107120Sjulian	bt3c_write(sc, 0x8040, 0x0404);
1127107120Sjulian	DELAY(17);
1128107120Sjulian
1129107120Sjulian	/* Download firmware */
1130107120Sjulian	device_printf(sc->dev, "Starting firmware download process...\n");
1131107120Sjulian
1132107120Sjulian	for (size = 0; size < firmware_size; ) {
1133107120Sjulian		block = (ng_bt3c_firmware_block_ep const *)(firmware + size);
1134107120Sjulian		data = (u_int16_t const *)(block + 1);
1135107120Sjulian
1136107120Sjulian		if (bootverbose)
1137107120Sjulian			device_printf(sc->dev, "Download firmware block, " \
1138107120Sjulian				"address=%#08x, size=%d words, aligment=%d\n",
1139107120Sjulian				block->block_address, block->block_size,
1140107120Sjulian				block->block_alignment);
1141107120Sjulian
1142107120Sjulian		bt3c_set_address(sc, block->block_address);
1143107120Sjulian		for (i = 0; i < block->block_size; i++)
1144107120Sjulian			bt3c_write_data(sc, data[i]);
1145107120Sjulian
1146107120Sjulian		size += (sizeof(*block) + (block->block_size * 2) +
1147107120Sjulian				block->block_alignment);
1148107120Sjulian	}
1149107120Sjulian
1150107120Sjulian	DELAY(17);
1151107120Sjulian	device_printf(sc->dev, "Firmware download process complete\n");
1152107120Sjulian
1153107120Sjulian	/* Boot */
1154107120Sjulian	device_printf(sc->dev, "Starting the card...\n");
1155107120Sjulian	bt3c_set_address(sc, 0x3000);
1156107120Sjulian	bt3c_read_control(sc, c);
1157107120Sjulian	bt3c_write_control(sc, (c | 0x40));
1158107120Sjulian	DELAY(17);
1159107120Sjulian
1160107120Sjulian	/* Clear registers */
1161107120Sjulian	device_printf(sc->dev, "Clearing card registers...\n");
1162107120Sjulian	bt3c_write(sc, 0x7006, 0x0000);
1163107120Sjulian	bt3c_write(sc, 0x7005, 0x0000);
1164107120Sjulian	bt3c_write(sc, 0x7001, 0x0000);
1165107120Sjulian	DELAY(1000);
1166107120Sjulian} /* bt3c_download_firmware */
1167107120Sjulian
1168107120Sjulian/****************************************************************************
1169107120Sjulian ****************************************************************************
1170107120Sjulian **                           Driver module
1171107120Sjulian ****************************************************************************
1172107120Sjulian ****************************************************************************/
1173107120Sjulian
1174107120Sjulian/*
1175150457Simp * PC Card (PCMCIA) driver
1176107120Sjulian */
1177107120Sjulian
1178107120Sjulianstatic device_method_t	bt3c_pccard_methods[] = {
1179107120Sjulian	/* Device interface */
1180150457Simp	DEVMETHOD(device_probe,		bt3c_pccard_probe),
1181150457Simp	DEVMETHOD(device_attach,	bt3c_pccard_attach),
1182107120Sjulian	DEVMETHOD(device_detach,	bt3c_pccard_detach),
1183107120Sjulian
1184107120Sjulian	{ 0, 0 }
1185107120Sjulian};
1186107120Sjulian
1187107120Sjulianstatic driver_t		bt3c_pccard_driver = {
1188107120Sjulian	NG_BT3C_NODE_TYPE,
1189107120Sjulian	bt3c_pccard_methods,
1190151726Semax	sizeof(bt3c_softc_t)
1191107120Sjulian};
1192107120Sjulian
1193107120Sjulianstatic devclass_t	bt3c_devclass;
1194107120Sjulian
1195114878Sjulian
1196114878Sjulian/*
1197114878Sjulian * Load/Unload the driver module
1198114878Sjulian */
1199114878Sjulian
1200114878Sjulianstatic int
1201114878Sjulianbt3c_modevent(module_t mod, int event, void *data)
1202114878Sjulian{
1203114878Sjulian	int	error;
1204114878Sjulian
1205114878Sjulian	switch (event) {
1206114878Sjulian	case MOD_LOAD:
1207114878Sjulian		error = ng_newtype(&typestruct);
1208114878Sjulian		if (error != 0)
1209114878Sjulian			printf("%s: Could not register Netgraph node type, " \
1210114878Sjulian				"error=%d\n", NG_BT3C_NODE_TYPE, error);
1211114878Sjulian		break;
1212107120Sjulian
1213114878Sjulian	case MOD_UNLOAD:
1214114878Sjulian		error = ng_rmtype(&typestruct);
1215114878Sjulian		break;
1216114878Sjulian
1217114878Sjulian	default:
1218114878Sjulian		error = EOPNOTSUPP;
1219114878Sjulian		break;
1220114878Sjulian	}
1221114878Sjulian
1222114878Sjulian	return (error);
1223114878Sjulian} /* bt3c_modevent */
1224114878Sjulian
1225114878SjulianDRIVER_MODULE(bt3c, pccard, bt3c_pccard_driver, bt3c_devclass, bt3c_modevent,0);
1226114878SjulianMODULE_VERSION(ng_bt3c, NG_BLUETOOTH_VERSION);
1227114878SjulianMODULE_DEPEND(ng_bt3c, netgraph, NG_ABI_VERSION, NG_ABI_VERSION,NG_ABI_VERSION);
1228114878Sjulian
1229