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