1139804Simp/* $FreeBSD$ */ 2126324Sjhb/*- 3126324Sjhb * Copyright (c) 2013 Hans Petter Selasky. All rights reserved. 4126324Sjhb * 5126324Sjhb * Redistribution and use in source and binary forms, with or without 6126324Sjhb * modification, are permitted provided that the following conditions 7126324Sjhb * are met: 8126324Sjhb * 1. Redistributions of source code must retain the above copyright 9126324Sjhb * notice, this list of conditions and the following disclaimer. 10126324Sjhb * 2. Redistributions in binary form must reproduce the above copyright 11126324Sjhb * notice, this list of conditions and the following disclaimer in the 12126324Sjhb * documentation and/or other materials provided with the distribution. 13126324Sjhb * 14126324Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15126324Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16126324Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17126324Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18126324Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19126324Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20126324Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21126324Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22126324Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23126324Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24126324Sjhb * SUCH DAMAGE. 25126324Sjhb */ 26126324Sjhb 27126324Sjhb#include <bsd_global.h> 28126324Sjhb 29126324Sjhbstruct usb_process usb_process[USB_PROC_MAX]; 30126324Sjhb 31126324Sjhbstatic device_t usb_pci_root; 32126324Sjhb 33126324Sjhb/*------------------------------------------------------------------------* 34126324Sjhb * Implementation of mutex API 35126324Sjhb *------------------------------------------------------------------------*/ 36126324Sjhb 37126324Sjhbstruct mtx Giant; 38126324Sjhb 39126324Sjhbstatic void 40126324Sjhbmtx_system_init(void *arg) 41126324Sjhb{ 42126324Sjhb mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE); 43126324Sjhb} 44126324SjhbSYSINIT(mtx_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, mtx_system_init, NULL); 45126324Sjhb 46126324Sjhbvoid 47126324Sjhbmtx_init(struct mtx *mtx, const char *name, const char *type, int opt) 48126324Sjhb{ 49126324Sjhb mtx->owned = 0; 50126324Sjhb mtx->parent = mtx; 51126324Sjhb} 52126324Sjhb 53126324Sjhbvoid 54126324Sjhbmtx_lock(struct mtx *mtx) 55126324Sjhb{ 56126324Sjhb mtx = mtx->parent; 57126324Sjhb mtx->owned++; 58126324Sjhb} 59126324Sjhb 60126324Sjhbvoid 61126324Sjhbmtx_unlock(struct mtx *mtx) 62126324Sjhb{ 63126324Sjhb mtx = mtx->parent; 64126324Sjhb mtx->owned--; 65154936Sjhb} 66154936Sjhb 67170640Sjeffint 68154936Sjhbmtx_owned(struct mtx *mtx) 69126324Sjhb{ 70126324Sjhb mtx = mtx->parent; 71126324Sjhb return (mtx->owned != 0); 72126324Sjhb} 73126324Sjhb 74126324Sjhbvoid 75126324Sjhbmtx_destroy(struct mtx *mtx) 76177372Sjeff{ 77126324Sjhb /* NOP */ 78126324Sjhb} 79126324Sjhb 80131259Sjhb/*------------------------------------------------------------------------* 81126324Sjhb * Implementation of shared/exclusive mutex API 82169666Sjeff *------------------------------------------------------------------------*/ 83169666Sjeff 84154936Sjhbvoid 85154936Sjhbsx_init_flags(struct sx *sx, const char *name, int flags) 86154936Sjhb{ 87154936Sjhb sx->owned = 0; 88126324Sjhb} 89126324Sjhb 90126324Sjhbvoid 91126324Sjhbsx_destroy(struct sx *sx) 92126324Sjhb{ 93126324Sjhb /* NOP */ 94126324Sjhb} 95126324Sjhb 96126324Sjhbvoid 97126324Sjhbsx_xlock(struct sx *sx) 98126324Sjhb{ 99126324Sjhb sx->owned++; 100165272Skmacy} 101126324Sjhb 102126324Sjhbvoid 103126324Sjhbsx_xunlock(struct sx *sx) 104126324Sjhb{ 105126324Sjhb sx->owned--; 106126324Sjhb} 107126324Sjhb 108126324Sjhbint 109126324Sjhbsx_xlocked(struct sx *sx) 110126324Sjhb{ 111126324Sjhb return (sx->owned != 0); 112126324Sjhb} 113126324Sjhb 114126324Sjhb/*------------------------------------------------------------------------* 115126324Sjhb * Implementaiton of condition variable API 116126324Sjhb *------------------------------------------------------------------------*/ 117126324Sjhb 118126324Sjhbvoid 119126324Sjhbcv_init(struct cv *cv, const char *desc) 120165272Skmacy{ 121126324Sjhb cv->sleeping = 0; 122126324Sjhb} 123126324Sjhb 124136445Sjhbvoid 125134013Sjhbcv_destroy(struct cv *cv) 126164325Spjd{ 127126324Sjhb /* NOP */ 128126324Sjhb} 129126324Sjhb 130126324Sjhbvoid 131126324Sjhbcv_wait(struct cv *cv, struct mtx *mtx) 132126324Sjhb{ 133131259Sjhb cv_timedwait(cv, mtx, -1); 134131259Sjhb} 135131259Sjhb 136131259Sjhbint 137126324Sjhbcv_timedwait(struct cv *cv, struct mtx *mtx, int timo) 138126324Sjhb{ 139131259Sjhb int start = ticks; 140131259Sjhb int delta; 141131259Sjhb 142131259Sjhb if (cv->sleeping) 143131259Sjhb return (EWOULDBLOCK); /* not allowed */ 144131259Sjhb 145131259Sjhb cv->sleeping = 1; 146177372Sjeff 147177372Sjeff while (cv->sleeping) { 148177372Sjeff if (timo >= 0) { 149131259Sjhb delta = ticks - start; 150126324Sjhb if (delta >= timo || delta < 0) 151169666Sjeff break; 152126324Sjhb } 153126324Sjhb mtx_unlock(mtx); 154126324Sjhb 155126324Sjhb usb_idle(); 156177085Sjeff 157165272Skmacy mtx_lock(mtx); 158126324Sjhb } 159169666Sjeff 160169666Sjeff if (cv->sleeping) { 161169666Sjeff cv->sleeping = 0; 162169666Sjeff return (EWOULDBLOCK); /* not allowed */ 163181334Sjhb } 164169666Sjeff return (0); 165177085Sjeff} 166126324Sjhb 167126324Sjhbvoid 168126324Sjhbcv_signal(struct cv *cv) 169126324Sjhb{ 170126324Sjhb cv->sleeping = 0; 171126324Sjhb} 172126324Sjhb 173126324Sjhbvoid 174126324Sjhbcv_broadcast(struct cv *cv) 175131259Sjhb{ 176131259Sjhb cv->sleeping = 0; 177131259Sjhb} 178131259Sjhb 179126324Sjhb/*------------------------------------------------------------------------* 180126324Sjhb * Implementation of callout API 181126324Sjhb *------------------------------------------------------------------------*/ 182126324Sjhb 183126324Sjhbstatic void callout_proc_msg(struct usb_proc_msg *); 184176258Sjhb 185131259Sjhbvolatile int ticks = 0; 186131259Sjhb 187131259Sjhbstatic LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout); 188131259Sjhb 189131259Sjhbstatic struct mtx mtx_callout; 190131259Sjhbstatic struct usb_proc_msg callout_msg[2]; 191131259Sjhb 192131259Sjhbstatic void 193131259Sjhbcallout_system_init(void *arg) 194131259Sjhb{ 195131259Sjhb mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE); 196126324Sjhb 197169666Sjeff callout_msg[0].pm_callback = &callout_proc_msg; 198169666Sjeff callout_msg[1].pm_callback = &callout_proc_msg; 199169666Sjeff} 200169666SjeffSYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL); 201169666Sjeff 202169666Sjeffstatic void 203169666Sjeffcallout_callback(struct callout *c) 204126324Sjhb{ 205126324Sjhb mtx_lock(c->mtx); 206126324Sjhb 207126324Sjhb mtx_lock(&mtx_callout); 208169666Sjeff if (c->entry.le_prev != NULL) { 209126324Sjhb LIST_REMOVE(c, entry); 210126324Sjhb c->entry.le_prev = NULL; 211126324Sjhb } 212126324Sjhb mtx_unlock(&mtx_callout); 213126324Sjhb 214169666Sjeff if (c->func) 215126324Sjhb (c->func) (c->arg); 216126324Sjhb 217126324Sjhb if (!(c->flags & CALLOUT_RETURNUNLOCKED)) 218126324Sjhb mtx_unlock(c->mtx); 219126324Sjhb} 220126324Sjhb 221126324Sjhbvoid 222126324Sjhbcallout_process(int timeout) 223126324Sjhb{ 224169666Sjeff ticks += timeout; 225126324Sjhb usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]); 226126324Sjhb} 227126324Sjhb 228136445Sjhbstatic void 229136445Sjhbcallout_proc_msg(struct usb_proc_msg *pmsg) 230136445Sjhb{ 231136445Sjhb struct callout *c; 232136445Sjhb int delta; 233136445Sjhb 234136445Sjhbrepeat: 235136445Sjhb mtx_lock(&mtx_callout); 236136445Sjhb 237136445Sjhb LIST_FOREACH(c, &head_callout, entry) { 238136445Sjhb 239136445Sjhb delta = c->timeout - ticks; 240126324Sjhb if (delta < 0) { 241136445Sjhb mtx_unlock(&mtx_callout); 242136445Sjhb 243126324Sjhb callout_callback(c); 244126324Sjhb 245126324Sjhb goto repeat; 246126324Sjhb } 247126324Sjhb } 248126324Sjhb mtx_unlock(&mtx_callout); 249126324Sjhb} 250126324Sjhb 251126324Sjhbvoid 252136445Sjhbcallout_init_mtx(struct callout *c, struct mtx *mtx, int flags) 253126324Sjhb{ 254126324Sjhb memset(c, 0, sizeof(*c)); 255126324Sjhb 256126324Sjhb if (mtx == NULL) 257126324Sjhb mtx = &Giant; 258126324Sjhb 259126324Sjhb c->mtx = mtx; 260126324Sjhb c->flags = (flags & CALLOUT_RETURNUNLOCKED); 261126324Sjhb} 262126324Sjhb 263126324Sjhbvoid 264126324Sjhbcallout_reset(struct callout *c, int to_ticks, 265126324Sjhb void (*func) (void *), void *arg) 266126324Sjhb{ 267126324Sjhb callout_stop(c); 268126324Sjhb 269126324Sjhb c->func = func; 270126324Sjhb c->arg = arg; 271126324Sjhb c->timeout = ticks + to_ticks; 272137277Sjhb 273126324Sjhb mtx_lock(&mtx_callout); 274126324Sjhb LIST_INSERT_HEAD(&head_callout, c, entry); 275126324Sjhb mtx_unlock(&mtx_callout); 276126324Sjhb} 277126324Sjhb 278165272Skmacyvoid 279165272Skmacycallout_stop(struct callout *c) 280126324Sjhb{ 281126324Sjhb mtx_lock(&mtx_callout); 282136445Sjhb 283137277Sjhb if (c->entry.le_prev != NULL) { 284126324Sjhb LIST_REMOVE(c, entry); 285126324Sjhb c->entry.le_prev = NULL; 286126324Sjhb } 287126324Sjhb mtx_unlock(&mtx_callout); 288126324Sjhb 289126324Sjhb c->func = NULL; 290165272Skmacy c->arg = NULL; 291126324Sjhb} 292150177Sjhb 293150177Sjhbvoid 294152221Simpcallout_drain(struct callout *c) 295150177Sjhb{ 296136445Sjhb if (c->mtx == NULL) 297136445Sjhb return; /* not initialised */ 298136445Sjhb 299136445Sjhb mtx_lock(c->mtx); 300136445Sjhb callout_stop(c); 301136445Sjhb mtx_unlock(c->mtx); 302136445Sjhb} 303136445Sjhb 304126324Sjhbint 305165272Skmacycallout_pending(struct callout *c) 306165292Skmacy{ 307165291Sache int retval; 308165292Skmacy 309165292Skmacy mtx_lock(&mtx_callout); 310165292Skmacy retval = (c->entry.le_prev != NULL); 311165272Skmacy mtx_unlock(&mtx_callout); 312165272Skmacy 313165272Skmacy return (retval); 314165272Skmacy} 315165292Skmacy 316165292Skmacy/*------------------------------------------------------------------------* 317165272Skmacy * Implementation of device API 318131259Sjhb *------------------------------------------------------------------------*/ 319131259Sjhb 320131259Sjhbstatic const char unknown_string[] = { "unknown" }; 321131259Sjhb 322131259Sjhbstatic TAILQ_HEAD(, module_data) module_head = 323131259Sjhb TAILQ_HEAD_INITIALIZER(module_head); 324131259Sjhb 325131259Sjhbstatic uint8_t 326165292Skmacydevclass_equal(const char *a, const char *b) 327126324Sjhb{ 328126324Sjhb char ta, tb; 329126324Sjhb 330126324Sjhb if (a == b) 331126488Sjhb return (1); 332136445Sjhb 333126324Sjhb while (1) { 334126324Sjhb ta = *a; 335172155Sattilio tb = *b; 336165272Skmacy if (ta != tb) 337126324Sjhb return (0); 338165272Skmacy if (ta == 0) 339126324Sjhb break; 340126324Sjhb a++; 341155741Sdavidxu b++; 342134013Sjhb } 343155741Sdavidxu return (1); 344155741Sdavidxu} 345172155Sattilio 346126324Sjhbint 347126324Sjhbbus_generic_resume(device_t dev) 348126324Sjhb{ 349126324Sjhb return (0); 350126324Sjhb} 351126324Sjhb 352126324Sjhbint 353126885Sjhbbus_generic_shutdown(device_t dev) 354126324Sjhb{ 355126324Sjhb return (0); 356126324Sjhb} 357126324Sjhb 358126324Sjhbint 359126324Sjhbbus_generic_suspend(device_t dev) 360126324Sjhb{ 361126324Sjhb return (0); 362126324Sjhb} 363126324Sjhb 364177860Sjeffint 365126324Sjhbbus_generic_print_child(device_t dev, device_t child) 366126324Sjhb{ 367126324Sjhb return (0); 368126324Sjhb} 369126324Sjhb 370170294Sjeffvoid 371170294Sjeffbus_generic_driver_added(device_t dev, driver_t *driver) 372126324Sjhb{ 373155741Sdavidxu return; 374177085Sjeff} 375126324Sjhb 376126324Sjhbdevice_t 377126324Sjhbdevice_get_parent(device_t dev) 378126324Sjhb{ 379126324Sjhb return (dev ? dev->dev_parent : NULL); 380155741Sdavidxu} 381155741Sdavidxu 382126324Sjhbvoid 383126324Sjhbdevice_set_interrupt(device_t dev, driver_filter_t *filter, 384155741Sdavidxu driver_intr_t *fn, void *arg) 385126324Sjhb{ 386126324Sjhb dev->dev_irq_filter = filter; 387126324Sjhb dev->dev_irq_fn = fn; 388177375Sjeff dev->dev_irq_arg = arg; 389177375Sjeff} 390177375Sjeff 391177375Sjeffvoid 392177375Sjeffdevice_run_interrupts(device_t parent) 393177375Sjeff{ 394177471Sjeff device_t child; 395177375Sjeff 396177375Sjeff if (parent == NULL) 397177375Sjeff return; 398177375Sjeff 399177375Sjeff TAILQ_FOREACH(child, &parent->dev_children, dev_link) { 400129241Sbde int status; 401173601Sjulian if (child->dev_irq_filter != NULL) 402126324Sjhb status = child->dev_irq_filter(child->dev_irq_arg); 403155741Sdavidxu else 404155741Sdavidxu status = FILTER_SCHEDULE_THREAD; 405126324Sjhb 406155741Sdavidxu if (status == FILTER_SCHEDULE_THREAD) { 407155741Sdavidxu if (child->dev_irq_fn != NULL) 408155741Sdavidxu (child->dev_irq_fn) (child->dev_irq_arg); 409155741Sdavidxu } 410155741Sdavidxu } 411155741Sdavidxu} 412155741Sdavidxu 413155741Sdavidxuvoid 414155741Sdavidxudevice_set_ivars(device_t dev, void *ivars) 415155741Sdavidxu{ 416155741Sdavidxu dev->dev_aux = ivars; 417184667Sdavidxu} 418184667Sdavidxu 419184667Sdavidxuvoid * 420184667Sdavidxudevice_get_ivars(device_t dev) 421184667Sdavidxu{ 422184667Sdavidxu return (dev ? dev->dev_aux : NULL); 423170294Sjeff} 424184667Sdavidxu 425170294Sjeffint 426184667Sdavidxudevice_get_unit(device_t dev) 427155936Sdavidxu{ 428155936Sdavidxu return (dev ? dev->dev_unit : 0); 429155936Sdavidxu} 430155936Sdavidxu 431170294Sjeffint 432170294Sjeffbus_generic_detach(device_t dev) 433181334Sjhb{ 434181334Sjhb device_t child; 435181334Sjhb int error; 436181334Sjhb 437181334Sjhb if (!dev->dev_attached) 438181334Sjhb return (EBUSY); 439181334Sjhb 440181334Sjhb TAILQ_FOREACH(child, &dev->dev_children, dev_link) { 441181334Sjhb if ((error = device_detach(child)) != 0) 442170294Sjeff return (error); 443170294Sjeff } 444170294Sjeff return (0); 445155741Sdavidxu} 446126324Sjhb 447126324Sjhbconst char * 448126324Sjhbdevice_get_nameunit(device_t dev) 449170294Sjeff{ 450170294Sjeff if (dev && dev->dev_nameunit[0]) 451126324Sjhb return (dev->dev_nameunit); 452126324Sjhb 453177085Sjeff return (unknown_string); 454126324Sjhb} 455126324Sjhb 456175654Sjhbstatic uint8_t 457126324Sjhbdevclass_create(devclass_t *dc_pp) 458126324Sjhb{ 459126324Sjhb if (dc_pp == NULL) { 460126324Sjhb return (1); 461126324Sjhb } 462170294Sjeff if (dc_pp[0] == NULL) { 463175654Sjhb dc_pp[0] = malloc(sizeof(**(dc_pp)), 464175654Sjhb M_DEVBUF, M_WAITOK | M_ZERO); 465175654Sjhb 466175654Sjhb if (dc_pp[0] == NULL) { 467175654Sjhb return (1); 468126324Sjhb } 469126324Sjhb } 470126324Sjhb return (0); 471126324Sjhb} 472175654Sjhb 473175654Sjhbstatic const struct module_data * 474175654Sjhbdevclass_find_create(const char *classname) 475175654Sjhb{ 476175654Sjhb const struct module_data *mod; 477175654Sjhb 478175654Sjhb TAILQ_FOREACH(mod, &module_head, entry) { 479175654Sjhb if (devclass_equal(mod->mod_name, classname)) { 480175654Sjhb if (devclass_create(mod->devclass_pp)) { 481181334Sjhb continue; 482181334Sjhb } 483181334Sjhb return (mod); 484181334Sjhb } 485181334Sjhb } 486181334Sjhb return (NULL); 487181334Sjhb} 488181334Sjhb 489181334Sjhbstatic uint8_t 490175654Sjhbdevclass_add_device(const struct module_data *mod, device_t dev) 491175654Sjhb{ 492175654Sjhb device_t *pp_dev; 493177372Sjeff device_t *end; 494177372Sjeff uint8_t unit; 495177372Sjeff 496177372Sjeff pp_dev = mod->devclass_pp[0]->dev_list; 497177085Sjeff end = pp_dev + DEVCLASS_MAXUNIT; 498177085Sjeff unit = 0; 499170294Sjeff 500126324Sjhb while (pp_dev != end) { 501178272Sjeff if (*pp_dev == NULL) { 502126324Sjhb *pp_dev = dev; 503129241Sbde dev->dev_unit = unit; 504173600Sjulian dev->dev_module = mod; 505126324Sjhb snprintf(dev->dev_nameunit, 506126324Sjhb sizeof(dev->dev_nameunit), 507126324Sjhb "%s%d", device_get_name(dev), unit); 508126324Sjhb return (0); 509126324Sjhb } 510126324Sjhb pp_dev++; 511126324Sjhb unit++; 512126324Sjhb } 513126324Sjhb DPRINTF("Could not add device to devclass.\n"); 514126324Sjhb return (1); 515126324Sjhb} 516170294Sjeff 517126324Sjhbstatic void 518126324Sjhbdevclass_delete_device(const struct module_data *mod, device_t dev) 519126324Sjhb{ 520126324Sjhb if (mod == NULL) { 521126324Sjhb return; 522126324Sjhb } 523126324Sjhb mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL; 524126324Sjhb dev->dev_module = NULL; 525126324Sjhb} 526126324Sjhb 527126324Sjhbstatic device_t 528126324Sjhbmake_device(device_t parent, const char *name) 529126324Sjhb{ 530126324Sjhb device_t dev = NULL; 531126324Sjhb const struct module_data *mod = NULL; 532126324Sjhb 533126324Sjhb if (name) { 534126324Sjhb 535126324Sjhb mod = devclass_find_create(name); 536126324Sjhb 537126324Sjhb if (!mod) { 538126324Sjhb 539126324Sjhb DPRINTF("%s:%d:%s: can't find device " 540126324Sjhb "class %s\n", __FILE__, __LINE__, 541178272Sjeff __FUNCTION__, name); 542126324Sjhb 543126324Sjhb goto done; 544126324Sjhb } 545126324Sjhb } 546126324Sjhb dev = malloc(sizeof(*dev), 547126324Sjhb M_DEVBUF, M_WAITOK | M_ZERO); 548126324Sjhb 549126324Sjhb if (dev == NULL) 550126324Sjhb goto done; 551126324Sjhb 552126324Sjhb dev->dev_parent = parent; 553126324Sjhb TAILQ_INIT(&dev->dev_children); 554126324Sjhb 555170294Sjeff if (name) { 556126324Sjhb dev->dev_fixed_class = 1; 557126324Sjhb if (devclass_add_device(mod, dev)) { 558155741Sdavidxu goto error; 559155741Sdavidxu } 560126324Sjhb } 561155741Sdavidxudone: 562155741Sdavidxu return (dev); 563155741Sdavidxu 564155741Sdavidxuerror: 565155741Sdavidxu if (dev) { 566126324Sjhb free(dev, M_DEVBUF); 567126324Sjhb } 568126324Sjhb return (NULL); 569126324Sjhb} 570126324Sjhb 571126324Sjhbdevice_t 572126324Sjhbdevice_add_child(device_t dev, const char *name, int unit) 573177085Sjeff{ 574126324Sjhb device_t child; 575170294Sjeff 576126324Sjhb if (unit != -1) { 577170294Sjeff device_printf(dev, "Unit is not -1\n"); 578170294Sjeff } 579170294Sjeff child = make_device(dev, name); 580177085Sjeff if (child == NULL) { 581170294Sjeff device_printf(dev, "Could not add child '%s'\n", name); 582126324Sjhb goto done; 583126324Sjhb } 584126324Sjhb if (dev == NULL) { 585126324Sjhb /* no parent */ 586126324Sjhb goto done; 587126324Sjhb } 588126324Sjhb TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link); 589177085Sjeffdone: 590126324Sjhb return (child); 591155741Sdavidxu} 592126324Sjhb 593126324Sjhbint 594177085Sjeffdevice_delete_child(device_t dev, device_t child) 595126324Sjhb{ 596170294Sjeff int error = 0; 597155741Sdavidxu device_t grandchild; 598155741Sdavidxu 599126324Sjhb /* remove children first */ 600126324Sjhb 601126324Sjhb while ((grandchild = TAILQ_FIRST(&child->dev_children))) { 602126324Sjhb error = device_delete_child(child, grandchild); 603126324Sjhb if (error) { 604126324Sjhb device_printf(dev, "Error deleting child!\n"); 605126324Sjhb goto done; 606126324Sjhb } 607177085Sjeff } 608126324Sjhb 609170294Sjeff error = device_detach(child); 610126324Sjhb 611126324Sjhb if (error) 612170294Sjeff goto done; 613170294Sjeff 614170294Sjeff devclass_delete_device(child->dev_module, child); 615177085Sjeff 616126324Sjhb if (dev != NULL) { 617170294Sjeff /* remove child from parent */ 618170294Sjeff TAILQ_REMOVE(&dev->dev_children, child, dev_link); 619131249Sjhb } 620126324Sjhb free(child, M_DEVBUF); 621126324Sjhb 622126324Sjhbdone: 623126324Sjhb return (error); 624126324Sjhb} 625126324Sjhb 626126324Sjhbint 627177085Sjeffdevice_delete_children(device_t dev) 628126324Sjhb{ 629155741Sdavidxu device_t child; 630126324Sjhb int error = 0; 631177085Sjeff 632126324Sjhb while ((child = TAILQ_FIRST(&dev->dev_children))) { 633126324Sjhb error = device_delete_child(dev, child); 634170294Sjeff if (error) { 635155741Sdavidxu device_printf(dev, "Error deleting child!\n"); 636155741Sdavidxu break; 637155741Sdavidxu } 638126324Sjhb } 639155741Sdavidxu return (error); 640126324Sjhb} 641126324Sjhb 642126324Sjhbvoid 643145056Sjhbdevice_quiet(device_t dev) 644145056Sjhb{ 645126324Sjhb dev->dev_quiet = 1; 646181334Sjhb} 647145056Sjhb 648126324Sjhbconst char * 649126324Sjhbdevice_get_desc(device_t dev) 650126324Sjhb{ 651126324Sjhb if (dev) 652126324Sjhb return &(dev->dev_desc[0]); 653126324Sjhb return (unknown_string); 654165272Skmacy} 655170294Sjeff 656126324Sjhbstatic int 657126324Sjhbdefault_method(void) 658126324Sjhb{ 659126324Sjhb /* do nothing */ 660165272Skmacy DPRINTF("Default method called\n"); 661126324Sjhb return (0); 662126324Sjhb} 663126324Sjhb 664126324Sjhbvoid * 665126324Sjhbdevice_get_method(device_t dev, const char *what) 666126324Sjhb{ 667126324Sjhb const struct device_method *mtod; 668126324Sjhb 669126324Sjhb mtod = dev->dev_module->driver->methods; 670126324Sjhb while (mtod->func != NULL) { 671126324Sjhb if (devclass_equal(mtod->desc, what)) { 672131259Sjhb return (mtod->func); 673131259Sjhb } 674131259Sjhb mtod++; 675126324Sjhb } 676126324Sjhb return ((void *)&default_method); 677126324Sjhb} 678126324Sjhb 679129188Sjhbconst char * 680129188Sjhbdevice_get_name(device_t dev) 681157743Sdavidxu{ 682129188Sjhb if (dev == NULL) 683129241Sbde return (unknown_string); 684173600Sjulian 685126324Sjhb return (dev->dev_module->driver->name); 686126324Sjhb} 687177085Sjeff 688177085Sjeffstatic int 689136439Supsdevice_allocate_softc(device_t dev) 690184653Sjhb{ 691184653Sjhb const struct module_data *mod; 692184653Sjhb 693184653Sjhb mod = dev->dev_module; 694184653Sjhb 695184653Sjhb if ((dev->dev_softc_alloc == 0) && 696184653Sjhb (mod->driver->size != 0)) { 697184653Sjhb dev->dev_sc = malloc(mod->driver->size, 698184653Sjhb M_DEVBUF, M_WAITOK | M_ZERO); 699184653Sjhb 700184653Sjhb if (dev->dev_sc == NULL) 701184653Sjhb return (ENOMEM); 702126324Sjhb 703126324Sjhb dev->dev_softc_alloc = 1; 704169666Sjeff } 705126324Sjhb return (0); 706169666Sjeff} 707169666Sjeff 708169666Sjeffint 709169666Sjeffdevice_probe_and_attach(device_t dev) 710169666Sjeff{ 711169666Sjeff const struct module_data *mod; 712169666Sjeff const char *bus_name_parent; 713169666Sjeff 714169666Sjeff bus_name_parent = device_get_name(device_get_parent(dev)); 715169666Sjeff 716169666Sjeff if (dev->dev_attached) 717169666Sjeff return (0); /* fail-safe */ 718169666Sjeff 719169666Sjeff if (dev->dev_fixed_class) { 720169666Sjeff 721169666Sjeff mod = dev->dev_module; 722169666Sjeff 723169666Sjeff if (DEVICE_PROBE(dev) <= 0) { 724169666Sjeff 725169666Sjeff if (device_allocate_softc(dev) == 0) { 726169666Sjeff 727169666Sjeff if (DEVICE_ATTACH(dev) == 0) { 728169666Sjeff /* success */ 729169666Sjeff dev->dev_attached = 1; 730169666Sjeff return (0); 731169666Sjeff } 732169666Sjeff } 733169666Sjeff } 734169666Sjeff device_detach(dev); 735169666Sjeff 736169666Sjeff goto error; 737169666Sjeff } 738126324Sjhb /* 739126324Sjhb * Else find a module for our device, if any 740181334Sjhb */ 741165272Skmacy 742126324Sjhb TAILQ_FOREACH(mod, &module_head, entry) { 743126324Sjhb if (devclass_equal(mod->bus_name, bus_name_parent)) { 744137277Sjhb if (devclass_create(mod->devclass_pp)) { 745181334Sjhb continue; 746126324Sjhb } 747126324Sjhb if (devclass_add_device(mod, dev)) { 748126324Sjhb continue; 749165272Skmacy } 750126324Sjhb if (DEVICE_PROBE(dev) <= 0) { 751170294Sjeff 752181334Sjhb if (device_allocate_softc(dev) == 0) { 753134013Sjhb 754126324Sjhb if (DEVICE_ATTACH(dev) == 0) { 755129188Sjhb /* success */ 756137277Sjhb dev->dev_attached = 1; 757137277Sjhb return (0); 758137277Sjhb } 759137277Sjhb } 760137277Sjhb } 761137277Sjhb /* else try next driver */ 762137277Sjhb 763165272Skmacy device_detach(dev); 764137277Sjhb } 765137277Sjhb } 766137277Sjhb 767137277Sjhberror: 768170294Sjeff return (ENODEV); 769181334Sjhb} 770170294Sjeff 771181334Sjhbint 772126324Sjhbdevice_detach(device_t dev) 773126324Sjhb{ 774126324Sjhb const struct module_data *mod = dev->dev_module; 775126324Sjhb int error; 776126324Sjhb 777181334Sjhb if (dev->dev_attached) { 778165272Skmacy 779126324Sjhb error = DEVICE_DETACH(dev); 780126324Sjhb if (error) { 781182875Sjhb return error; 782181334Sjhb } 783126324Sjhb dev->dev_attached = 0; 784126324Sjhb } 785126324Sjhb device_set_softc(dev, NULL); 786165272Skmacy 787126324Sjhb if (dev->dev_fixed_class == 0) 788177085Sjeff devclass_delete_device(mod, dev); 789181334Sjhb 790134013Sjhb return (0); 791126324Sjhb} 792129188Sjhb 793145056Sjhbvoid 794181334Sjhbdevice_set_softc(device_t dev, void *softc) 795182875Sjhb{ 796170294Sjeff if (dev->dev_softc_alloc) { 797181334Sjhb free(dev->dev_sc, M_DEVBUF); 798181334Sjhb dev->dev_sc = NULL; 799170294Sjeff } 800170294Sjeff dev->dev_sc = softc; 801181334Sjhb dev->dev_softc_alloc = 0; 802126324Sjhb} 803126324Sjhb 804126324Sjhbvoid * 805126324Sjhbdevice_get_softc(device_t dev) 806126324Sjhb{ 807126324Sjhb if (dev == NULL) 808126324Sjhb return (NULL); 809126324Sjhb 810126324Sjhb return (dev->dev_sc); 811170294Sjeff} 812126324Sjhb 813126324Sjhbint 814126324Sjhbdevice_is_attached(device_t dev) 815181334Sjhb{ 816126324Sjhb return (dev->dev_attached); 817129241Sbde} 818181334Sjhb 819129241Sbdevoid 820173600Sjuliandevice_set_desc(device_t dev, const char *desc) 821126324Sjhb{ 822126324Sjhb snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc); 823126324Sjhb} 824126324Sjhb 825126324Sjhbvoid 826170294Sjeffdevice_set_desc_copy(device_t dev, const char *desc) 827170294Sjeff{ 828126324Sjhb device_set_desc(dev, desc); 829170294Sjeff} 830176078Sjeff 831126324Sjhbvoid * 832170294Sjeffdevclass_get_softc(devclass_t dc, int unit) 833170294Sjeff{ 834181334Sjhb return (device_get_softc(devclass_get_device(dc, unit))); 835170294Sjeff} 836181334Sjhb 837181334Sjhbint 838170294Sjeffdevclass_get_maxunit(devclass_t dc) 839126324Sjhb{ 840175654Sjhb int max_unit = 0; 841126324Sjhb 842175654Sjhb if (dc) { 843175654Sjhb max_unit = DEVCLASS_MAXUNIT; 844175654Sjhb while (max_unit--) { 845175654Sjhb if (dc->dev_list[max_unit]) { 846126324Sjhb break; 847126324Sjhb } 848175664Sjhb } 849170294Sjeff max_unit++; 850126324Sjhb } 851170294Sjeff return (max_unit); 852126324Sjhb} 853126324Sjhb 854126324Sjhbdevice_t 855126324Sjhbdevclass_get_device(devclass_t dc, int unit) 856126324Sjhb{ 857126324Sjhb return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ? 858126324Sjhb NULL : dc->dev_list[unit]); 859126324Sjhb} 860126324Sjhb 861126324Sjhbdevclass_t 862126324Sjhbdevclass_find(const char *classname) 863127085Sjhb{ 864126324Sjhb const struct module_data *mod; 865126324Sjhb 866181334Sjhb TAILQ_FOREACH(mod, &module_head, entry) { 867126324Sjhb if (devclass_equal(mod->mod_name, classname)) 868126324Sjhb return (mod->devclass_pp[0]); 869170294Sjeff } 870181334Sjhb return (NULL); 871181334Sjhb} 872126324Sjhb 873126324Sjhbvoid 874126324Sjhbmodule_register(void *data) 875126324Sjhb{ 876126324Sjhb struct module_data *mdata = data; 877126324Sjhb 878126324Sjhb TAILQ_INSERT_TAIL(&module_head, mdata, entry); 879126324Sjhb} 880126324Sjhb 881126324Sjhb/*------------------------------------------------------------------------* 882181334Sjhb * System startup 883126324Sjhb *------------------------------------------------------------------------*/ 884126324Sjhb 885126324Sjhbstatic void 886126324Sjhbsysinit_run(const void **ppdata) 887126324Sjhb{ 888126324Sjhb const struct sysinit *psys; 889126324Sjhb 890136445Sjhb while ((psys = *ppdata) != NULL) { 891126324Sjhb (psys->func) (psys->data); 892170294Sjeff ppdata++; 893170294Sjeff } 894170294Sjeff} 895170294Sjeff 896170294Sjeff/*------------------------------------------------------------------------* 897170294Sjeff * USB process API 898126324Sjhb *------------------------------------------------------------------------*/ 899126324Sjhb 900126324Sjhbstatic int usb_do_process(struct usb_process *); 901126324Sjhbstatic int usb_proc_level = -1; 902170294Sjeffstatic struct mtx usb_proc_mtx; 903170294Sjeff 904126324Sjhbvoid 905170294Sjeffusb_idle(void) 906181334Sjhb{ 907170294Sjeff int old_level = usb_proc_level; 908126324Sjhb int old_giant = Giant.owned; 909181334Sjhb int worked; 910181334Sjhb 911126324Sjhb device_run_interrupts(usb_pci_root); 912126324Sjhb 913126324Sjhb do { 914129241Sbde worked = 0; 915129241Sbde Giant.owned = 0; 916126324Sjhb 917181334Sjhb while (++usb_proc_level < USB_PROC_MAX) 918155741Sdavidxu worked |= usb_do_process(usb_process + usb_proc_level); 919126324Sjhb 920170294Sjeff usb_proc_level = old_level; 921126324Sjhb Giant.owned = old_giant; 922126324Sjhb 923170294Sjeff } while (worked); 924126324Sjhb} 925126324Sjhb 926155741Sdavidxuvoid 927126324Sjhbusb_init(void) 928126324Sjhb{ 929126324Sjhb sysinit_run(sysinit_data); 930126324Sjhb} 931126324Sjhb 932126324Sjhbvoid 933181334Sjhbusb_uninit(void) 934126324Sjhb{ 935129241Sbde sysinit_run(sysuninit_data); 936173600Sjulian} 937170294Sjeff 938170294Sjeffstatic void 939170294Sjeffusb_process_init_sub(struct usb_process *up) 940170294Sjeff{ 941170294Sjeff TAILQ_INIT(&up->up_qhead); 942170294Sjeff 943170294Sjeff cv_init(&up->up_cv, "-"); 944170294Sjeff cv_init(&up->up_drain, "usbdrain"); 945181334Sjhb 946126324Sjhb up->up_mtx = &usb_proc_mtx; 947170294Sjeff} 948170294Sjeff 949170294Sjeffstatic void 950170294Sjeffusb_process_init(void *arg) 951170294Sjeff{ 952181334Sjhb uint8_t x; 953126324Sjhb 954154936Sjhb mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE); 955177372Sjeff 956177372Sjeff for (x = 0; x != USB_PROC_MAX; x++) 957177372Sjeff usb_process_init_sub(&usb_process[x]); 958177372Sjeff 959177372Sjeff} 960177372SjeffSYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL); 961177372Sjeff 962177372Sjeffstatic int 963177372Sjeffusb_do_process(struct usb_process *up) 964177372Sjeff{ 965177372Sjeff struct usb_proc_msg *pm; 966177372Sjeff int worked = 0; 967177372Sjeff 968177372Sjeff mtx_lock(&usb_proc_mtx); 969177372Sjeff 970177372Sjeffrepeat: 971177372Sjeff pm = TAILQ_FIRST(&up->up_qhead); 972177372Sjeff 973177372Sjeff if (pm != NULL) { 974177372Sjeff 975177372Sjeff worked = 1; 976177372Sjeff 977177372Sjeff (pm->pm_callback) (pm); 978177372Sjeff 979177372Sjeff if (pm == TAILQ_FIRST(&up->up_qhead)) { 980177372Sjeff /* nothing changed */ 981177372Sjeff TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); 982177372Sjeff pm->pm_qentry.tqe_prev = NULL; 983177372Sjeff } 984177372Sjeff goto repeat; 985177372Sjeff } 986177372Sjeff mtx_unlock(&usb_proc_mtx); 987177372Sjeff 988177372Sjeff return (worked); 989177372Sjeff} 990177372Sjeff 991177372Sjeffvoid * 992177372Sjeffusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1) 993177372Sjeff{ 994177372Sjeff struct usb_proc_msg *pm0 = _pm0; 995177372Sjeff struct usb_proc_msg *pm1 = _pm1; 996177372Sjeff struct usb_proc_msg *pm2; 997177372Sjeff usb_size_t d; 998177372Sjeff uint8_t t; 999177372Sjeff 1000177372Sjeff t = 0; 1001177372Sjeff 1002177372Sjeff if (pm0->pm_qentry.tqe_prev) { 1003177372Sjeff t |= 1; 1004177372Sjeff } 1005177372Sjeff if (pm1->pm_qentry.tqe_prev) { 1006177372Sjeff t |= 2; 1007177372Sjeff } 1008177372Sjeff if (t == 0) { 1009177372Sjeff /* 1010177372Sjeff * No entries are queued. Queue "pm0" and use the existing 1011177372Sjeff * message number. 1012177372Sjeff */ 1013177372Sjeff pm2 = pm0; 1014177372Sjeff } else if (t == 1) { 1015177372Sjeff /* Check if we need to increment the message number. */ 1016177372Sjeff if (pm0->pm_num == up->up_msg_num) { 1017177372Sjeff up->up_msg_num++; 1018177372Sjeff } 1019177372Sjeff pm2 = pm1; 1020177372Sjeff } else if (t == 2) { 1021177372Sjeff /* Check if we need to increment the message number. */ 1022177372Sjeff if (pm1->pm_num == up->up_msg_num) { 1023177372Sjeff up->up_msg_num++; 1024177372Sjeff } 1025177372Sjeff pm2 = pm0; 1026177372Sjeff } else if (t == 3) { 1027177372Sjeff /* 1028177372Sjeff * Both entries are queued. Re-queue the entry closest to 1029177372Sjeff * the end. 1030177372Sjeff */ 1031177372Sjeff d = (pm1->pm_num - pm0->pm_num); 1032177372Sjeff 1033177372Sjeff /* Check sign after subtraction */ 1034177372Sjeff if (d & 0x80000000) { 1035177372Sjeff pm2 = pm0; 1036177372Sjeff } else { 1037177372Sjeff pm2 = pm1; 1038177372Sjeff } 1039177372Sjeff 1040177372Sjeff TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry); 1041177372Sjeff } else { 1042177372Sjeff pm2 = NULL; /* panic - should not happen */ 1043177372Sjeff } 1044177372Sjeff 1045177372Sjeff /* Put message last on queue */ 1046177372Sjeff 1047177372Sjeff pm2->pm_num = up->up_msg_num; 1048177372Sjeff TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry); 1049177372Sjeff 1050177372Sjeff return (pm2); 1051177372Sjeff} 1052177372Sjeff 1053177372Sjeff/*------------------------------------------------------------------------* 1054177372Sjeff * usb_proc_is_gone 1055177372Sjeff * 1056177372Sjeff * Return values: 1057177372Sjeff * 0: USB process is running 1058177372Sjeff * Else: USB process is tearing down 1059177372Sjeff *------------------------------------------------------------------------*/ 1060177372Sjeffuint8_t 1061177372Sjeffusb_proc_is_gone(struct usb_process *up) 1062177372Sjeff{ 1063177372Sjeff return (0); 1064177372Sjeff} 1065177372Sjeff 1066177372Sjeff/*------------------------------------------------------------------------* 1067177372Sjeff * usb_proc_mwait 1068177372Sjeff * 1069177372Sjeff * This function will return when the USB process message pointed to 1070177372Sjeff * by "pm" is no longer on a queue. This function must be called 1071177372Sjeff * having "usb_proc_mtx" locked. 1072177372Sjeff *------------------------------------------------------------------------*/ 1073177372Sjeffvoid 1074177372Sjeffusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1) 1075177372Sjeff{ 1076177372Sjeff struct usb_proc_msg *pm0 = _pm0; 1077177372Sjeff struct usb_proc_msg *pm1 = _pm1; 1078177372Sjeff 1079177372Sjeff /* Just remove the messages from the queue. */ 1080177372Sjeff if (pm0->pm_qentry.tqe_prev) { 1081177372Sjeff TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry); 1082177372Sjeff pm0->pm_qentry.tqe_prev = NULL; 1083177372Sjeff } 1084177372Sjeff if (pm1->pm_qentry.tqe_prev) { 1085177372Sjeff TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry); 1086177372Sjeff pm1->pm_qentry.tqe_prev = NULL; 1087177372Sjeff } 1088177372Sjeff} 1089177372Sjeff 1090177372Sjeff/*------------------------------------------------------------------------* 1091177372Sjeff * SYSTEM attach 1092177372Sjeff *------------------------------------------------------------------------*/ 1093177372Sjeff 1094177372Sjeffstatic device_method_t pci_methods[] = { 1095177372Sjeff DEVMETHOD_END 1096177372Sjeff}; 1097177372Sjeff 1098177372Sjeffstatic driver_t pci_driver = { 1099177372Sjeff .name = "pci", 1100177372Sjeff .methods = pci_methods, 1101177372Sjeff}; 1102177372Sjeff 1103177372Sjeffstatic devclass_t pci_devclass; 1104177372Sjeff 1105177372SjeffDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0); 1106154936Sjhb 1107154936Sjhbstatic const char *usb_pci_devices[] = { 1108154936Sjhb#ifdef USB_PROBE_LIST 1109154936Sjhb USB_PROBE_LIST 1110154936Sjhb#endif 1111154944Simp}; 1112154936Sjhb 1113154944Simp#define USB_PCI_USB_MAX (sizeof(usb_pci_devices) / sizeof(void *)) 1114154936Sjhb 1115154936Sjhbstatic device_t usb_pci_dev[USB_PCI_USB_MAX]; 1116154936Sjhb 1117154936Sjhbstatic void 1118154936Sjhbusb_pci_mod_load(void *arg) 1119154936Sjhb{ 1120154936Sjhb uint32_t x; 1121154936Sjhb 1122154936Sjhb usb_pci_root = device_add_child(NULL, "pci", -1); 1123154936Sjhb if (usb_pci_root == NULL) 1124154936Sjhb return; 1125154936Sjhb 1126154936Sjhb for (x = 0; x != USB_PCI_USB_MAX; x++) { 1127154936Sjhb usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1); 1128154936Sjhb if (usb_pci_dev[x] == NULL) 1129154936Sjhb continue; 1130154936Sjhb if (device_probe_and_attach(usb_pci_dev[x])) { 1131154936Sjhb device_printf(usb_pci_dev[x], 1132154936Sjhb "WARNING: Probe and attach failed!\n"); 1133154936Sjhb } 1134154936Sjhb } 1135154936Sjhb} 1136154936SjhbSYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0); 1137154936Sjhb 1138154936Sjhbstatic void 1139154936Sjhbusb_pci_mod_unload(void *arg) 1140154936Sjhb{ 1141154936Sjhb uint32_t x; 1142154936Sjhb 1143154936Sjhb for (x = 0; x != USB_PCI_USB_MAX; x++) { 1144154936Sjhb if (usb_pci_dev[x]) { 1145154936Sjhb device_detach(usb_pci_dev[x]); 1146154936Sjhb device_delete_child(usb_pci_root, usb_pci_dev[x]); 1147154936Sjhb } 1148164325Spjd } 1149154936Sjhb if (usb_pci_root) 1150154936Sjhb device_delete_child(NULL, usb_pci_root); 1151154936Sjhb} 1152154936SjhbSYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0); 1153154936Sjhb 1154165272Skmacy/*------------------------------------------------------------------------* 1155165272Skmacy * MALLOC API 1156165272Skmacy *------------------------------------------------------------------------*/ 1157165272Skmacy 1158165272Skmacy#define USB_POOL_ALIGN 8 1159165272Skmacy 1160165272Skmacystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN); 1161165272Skmacystatic uint32_t usb_pool_rem = USB_POOL_SIZE; 1162165272Skmacystatic uint32_t usb_pool_entries; 1163180930Sjhb 1164165272Skmacystruct malloc_hdr { 1165165272Skmacy TAILQ_ENTRY(malloc_hdr) entry; 1166154936Sjhb uint32_t size; 1167157823Sjhb} __aligned(USB_POOL_ALIGN); 1168157823Sjhb 1169183054Ssamstatic TAILQ_HEAD(, malloc_hdr) malloc_head = 1170154936Sjhb TAILQ_HEAD_INITIALIZER(malloc_head); 1171 1172void * 1173usb_malloc(unsigned long size) 1174{ 1175 struct malloc_hdr *hdr; 1176 1177 size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1); 1178 size += sizeof(struct malloc_hdr); 1179 1180 TAILQ_FOREACH(hdr, &malloc_head, entry) { 1181 if (hdr->size == size) 1182 break; 1183 } 1184 1185 if (hdr) { 1186 printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1187 (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1188 1189 TAILQ_REMOVE(&malloc_head, hdr, entry); 1190 memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1191 return (hdr + 1); 1192 } 1193 if (usb_pool_rem >= size) { 1194 hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem); 1195 hdr->size = size; 1196 1197 usb_pool_rem -= size; 1198 usb_pool_entries++; 1199 1200 printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1201 (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1202 1203 memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1204 return (hdr + 1); 1205 } 1206 return (NULL); 1207} 1208 1209void 1210usb_free(void *arg) 1211{ 1212 struct malloc_hdr *hdr; 1213 1214 if (arg == NULL) 1215 return; 1216 1217 hdr = arg; 1218 hdr--; 1219 1220 TAILQ_INSERT_TAIL(&malloc_head, hdr, entry); 1221} 1222 1223char * 1224usb_strdup(const char *str) 1225{ 1226 char *tmp; 1227 int len; 1228 1229 len = 1 + strlen(str); 1230 1231 tmp = usb_malloc(len); 1232 if (tmp == NULL) 1233 return (NULL); 1234 1235 memcpy(tmp, str, len); 1236 return (tmp); 1237} 1238