bsd_kernel.c revision 291403
1246145Shselasky/* $FreeBSD: head/sys/boot/kshim/bsd_kernel.c 291403 2015-11-27 18:19:11Z zbb $ */ 2246145Shselasky/*- 3246145Shselasky * Copyright (c) 2013 Hans Petter Selasky. All rights reserved. 4246145Shselasky * 5246145Shselasky * Redistribution and use in source and binary forms, with or without 6246145Shselasky * modification, are permitted provided that the following conditions 7246145Shselasky * are met: 8246145Shselasky * 1. Redistributions of source code must retain the above copyright 9246145Shselasky * notice, this list of conditions and the following disclaimer. 10246145Shselasky * 2. Redistributions in binary form must reproduce the above copyright 11246145Shselasky * notice, this list of conditions and the following disclaimer in the 12246145Shselasky * documentation and/or other materials provided with the distribution. 13246145Shselasky * 14246145Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15246145Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16246145Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17246145Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18246145Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19246145Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20246145Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21246145Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22246145Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23246145Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24246145Shselasky * SUCH DAMAGE. 25246145Shselasky */ 26246145Shselasky 27246145Shselasky#include <bsd_global.h> 28246145Shselasky 29246363Shselaskystruct usb_process usb_process[USB_PROC_MAX]; 30246363Shselasky 31246145Shselaskystatic device_t usb_pci_root; 32246145Shselasky 33246145Shselasky/*------------------------------------------------------------------------* 34246145Shselasky * Implementation of mutex API 35246145Shselasky *------------------------------------------------------------------------*/ 36246145Shselasky 37246145Shselaskystruct mtx Giant; 38246145Shselasky 39246145Shselaskystatic void 40246145Shselaskymtx_system_init(void *arg) 41246145Shselasky{ 42246145Shselasky mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE); 43246145Shselasky} 44246145ShselaskySYSINIT(mtx_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, mtx_system_init, NULL); 45246145Shselasky 46246145Shselaskyvoid 47246145Shselaskymtx_init(struct mtx *mtx, const char *name, const char *type, int opt) 48246145Shselasky{ 49246145Shselasky mtx->owned = 0; 50246145Shselasky mtx->parent = mtx; 51246145Shselasky} 52246145Shselasky 53246145Shselaskyvoid 54246145Shselaskymtx_lock(struct mtx *mtx) 55246145Shselasky{ 56246145Shselasky mtx = mtx->parent; 57246145Shselasky mtx->owned++; 58246145Shselasky} 59246145Shselasky 60246145Shselaskyvoid 61246145Shselaskymtx_unlock(struct mtx *mtx) 62246145Shselasky{ 63246145Shselasky mtx = mtx->parent; 64246145Shselasky mtx->owned--; 65246145Shselasky} 66246145Shselasky 67246145Shselaskyint 68246145Shselaskymtx_owned(struct mtx *mtx) 69246145Shselasky{ 70246145Shselasky mtx = mtx->parent; 71246145Shselasky return (mtx->owned != 0); 72246145Shselasky} 73246145Shselasky 74246145Shselaskyvoid 75246145Shselaskymtx_destroy(struct mtx *mtx) 76246145Shselasky{ 77246145Shselasky /* NOP */ 78246145Shselasky} 79246145Shselasky 80246145Shselasky/*------------------------------------------------------------------------* 81246145Shselasky * Implementation of shared/exclusive mutex API 82246145Shselasky *------------------------------------------------------------------------*/ 83246145Shselasky 84246145Shselaskyvoid 85246145Shselaskysx_init_flags(struct sx *sx, const char *name, int flags) 86246145Shselasky{ 87246145Shselasky sx->owned = 0; 88246145Shselasky} 89246145Shselasky 90246145Shselaskyvoid 91246145Shselaskysx_destroy(struct sx *sx) 92246145Shselasky{ 93246145Shselasky /* NOP */ 94246145Shselasky} 95246145Shselasky 96246145Shselaskyvoid 97246145Shselaskysx_xlock(struct sx *sx) 98246145Shselasky{ 99246145Shselasky sx->owned++; 100246145Shselasky} 101246145Shselasky 102246145Shselaskyvoid 103246145Shselaskysx_xunlock(struct sx *sx) 104246145Shselasky{ 105246145Shselasky sx->owned--; 106246145Shselasky} 107246145Shselasky 108246145Shselaskyint 109246145Shselaskysx_xlocked(struct sx *sx) 110246145Shselasky{ 111246145Shselasky return (sx->owned != 0); 112246145Shselasky} 113246145Shselasky 114246145Shselasky/*------------------------------------------------------------------------* 115246145Shselasky * Implementaiton of condition variable API 116246145Shselasky *------------------------------------------------------------------------*/ 117246145Shselasky 118246145Shselaskyvoid 119246145Shselaskycv_init(struct cv *cv, const char *desc) 120246145Shselasky{ 121246145Shselasky cv->sleeping = 0; 122246145Shselasky} 123246145Shselasky 124246145Shselaskyvoid 125246145Shselaskycv_destroy(struct cv *cv) 126246145Shselasky{ 127246145Shselasky /* NOP */ 128246145Shselasky} 129246145Shselasky 130246145Shselaskyvoid 131246145Shselaskycv_wait(struct cv *cv, struct mtx *mtx) 132246145Shselasky{ 133246145Shselasky cv_timedwait(cv, mtx, -1); 134246145Shselasky} 135246145Shselasky 136246145Shselaskyint 137246145Shselaskycv_timedwait(struct cv *cv, struct mtx *mtx, int timo) 138246145Shselasky{ 139246145Shselasky int start = ticks; 140246145Shselasky int delta; 141291403Szbb int time = 0; 142246145Shselasky 143246145Shselasky if (cv->sleeping) 144246145Shselasky return (EWOULDBLOCK); /* not allowed */ 145246145Shselasky 146246145Shselasky cv->sleeping = 1; 147246145Shselasky 148246145Shselasky while (cv->sleeping) { 149246145Shselasky if (timo >= 0) { 150246145Shselasky delta = ticks - start; 151246145Shselasky if (delta >= timo || delta < 0) 152246145Shselasky break; 153246145Shselasky } 154246145Shselasky mtx_unlock(mtx); 155246145Shselasky 156246145Shselasky usb_idle(); 157246145Shselasky 158291403Szbb if (++time >= (1000000 / hz)) { 159291403Szbb time = 0; 160291403Szbb callout_process(1); 161291403Szbb } 162291403Szbb 163291403Szbb /* Sleep for 1 us */ 164291403Szbb delay(1); 165291403Szbb 166246145Shselasky mtx_lock(mtx); 167246145Shselasky } 168246145Shselasky 169246145Shselasky if (cv->sleeping) { 170246145Shselasky cv->sleeping = 0; 171246145Shselasky return (EWOULDBLOCK); /* not allowed */ 172246145Shselasky } 173246145Shselasky return (0); 174246145Shselasky} 175246145Shselasky 176246145Shselaskyvoid 177246145Shselaskycv_signal(struct cv *cv) 178246145Shselasky{ 179246145Shselasky cv->sleeping = 0; 180246145Shselasky} 181246145Shselasky 182246145Shselaskyvoid 183246145Shselaskycv_broadcast(struct cv *cv) 184246145Shselasky{ 185246145Shselasky cv->sleeping = 0; 186246145Shselasky} 187246145Shselasky 188246145Shselasky/*------------------------------------------------------------------------* 189246145Shselasky * Implementation of callout API 190246145Shselasky *------------------------------------------------------------------------*/ 191246145Shselasky 192246145Shselaskystatic void callout_proc_msg(struct usb_proc_msg *); 193246145Shselasky 194246145Shselaskyvolatile int ticks = 0; 195246145Shselasky 196246145Shselaskystatic LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout); 197246145Shselasky 198246145Shselaskystatic struct mtx mtx_callout; 199246145Shselaskystatic struct usb_proc_msg callout_msg[2]; 200246145Shselasky 201246145Shselaskystatic void 202246145Shselaskycallout_system_init(void *arg) 203246145Shselasky{ 204246145Shselasky mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE); 205246145Shselasky 206246145Shselasky callout_msg[0].pm_callback = &callout_proc_msg; 207246145Shselasky callout_msg[1].pm_callback = &callout_proc_msg; 208246145Shselasky} 209246145ShselaskySYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL); 210246145Shselasky 211246145Shselaskystatic void 212246145Shselaskycallout_callback(struct callout *c) 213246145Shselasky{ 214246145Shselasky mtx_lock(c->mtx); 215246145Shselasky 216246145Shselasky mtx_lock(&mtx_callout); 217246145Shselasky if (c->entry.le_prev != NULL) { 218246145Shselasky LIST_REMOVE(c, entry); 219246145Shselasky c->entry.le_prev = NULL; 220246145Shselasky } 221246145Shselasky mtx_unlock(&mtx_callout); 222246145Shselasky 223246145Shselasky if (c->func) 224246145Shselasky (c->func) (c->arg); 225246145Shselasky 226246145Shselasky if (!(c->flags & CALLOUT_RETURNUNLOCKED)) 227246145Shselasky mtx_unlock(c->mtx); 228246145Shselasky} 229246145Shselasky 230246145Shselaskyvoid 231246145Shselaskycallout_process(int timeout) 232246145Shselasky{ 233246145Shselasky ticks += timeout; 234246145Shselasky usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]); 235246145Shselasky} 236246145Shselasky 237246145Shselaskystatic void 238246145Shselaskycallout_proc_msg(struct usb_proc_msg *pmsg) 239246145Shselasky{ 240246145Shselasky struct callout *c; 241246145Shselasky int delta; 242246145Shselasky 243246145Shselaskyrepeat: 244246145Shselasky mtx_lock(&mtx_callout); 245246145Shselasky 246246145Shselasky LIST_FOREACH(c, &head_callout, entry) { 247246145Shselasky 248246145Shselasky delta = c->timeout - ticks; 249246145Shselasky if (delta < 0) { 250246145Shselasky mtx_unlock(&mtx_callout); 251246145Shselasky 252246145Shselasky callout_callback(c); 253246145Shselasky 254246145Shselasky goto repeat; 255246145Shselasky } 256246145Shselasky } 257246145Shselasky mtx_unlock(&mtx_callout); 258246145Shselasky} 259246145Shselasky 260246145Shselaskyvoid 261246145Shselaskycallout_init_mtx(struct callout *c, struct mtx *mtx, int flags) 262246145Shselasky{ 263246145Shselasky memset(c, 0, sizeof(*c)); 264246145Shselasky 265246145Shselasky if (mtx == NULL) 266246145Shselasky mtx = &Giant; 267246145Shselasky 268246145Shselasky c->mtx = mtx; 269246145Shselasky c->flags = (flags & CALLOUT_RETURNUNLOCKED); 270246145Shselasky} 271246145Shselasky 272246145Shselaskyvoid 273246145Shselaskycallout_reset(struct callout *c, int to_ticks, 274246145Shselasky void (*func) (void *), void *arg) 275246145Shselasky{ 276246145Shselasky callout_stop(c); 277246145Shselasky 278246145Shselasky c->func = func; 279246145Shselasky c->arg = arg; 280246145Shselasky c->timeout = ticks + to_ticks; 281246145Shselasky 282246145Shselasky mtx_lock(&mtx_callout); 283246145Shselasky LIST_INSERT_HEAD(&head_callout, c, entry); 284246145Shselasky mtx_unlock(&mtx_callout); 285246145Shselasky} 286246145Shselasky 287246145Shselaskyvoid 288246145Shselaskycallout_stop(struct callout *c) 289246145Shselasky{ 290246145Shselasky mtx_lock(&mtx_callout); 291246145Shselasky 292246145Shselasky if (c->entry.le_prev != NULL) { 293246145Shselasky LIST_REMOVE(c, entry); 294246145Shselasky c->entry.le_prev = NULL; 295246145Shselasky } 296246145Shselasky mtx_unlock(&mtx_callout); 297246145Shselasky 298246145Shselasky c->func = NULL; 299246145Shselasky c->arg = NULL; 300246145Shselasky} 301246145Shselasky 302246145Shselaskyvoid 303246145Shselaskycallout_drain(struct callout *c) 304246145Shselasky{ 305246145Shselasky if (c->mtx == NULL) 306246145Shselasky return; /* not initialised */ 307246145Shselasky 308246145Shselasky mtx_lock(c->mtx); 309246145Shselasky callout_stop(c); 310246145Shselasky mtx_unlock(c->mtx); 311246145Shselasky} 312246145Shselasky 313246145Shselaskyint 314246145Shselaskycallout_pending(struct callout *c) 315246145Shselasky{ 316246145Shselasky int retval; 317246145Shselasky 318246145Shselasky mtx_lock(&mtx_callout); 319246145Shselasky retval = (c->entry.le_prev != NULL); 320246145Shselasky mtx_unlock(&mtx_callout); 321246145Shselasky 322246145Shselasky return (retval); 323246145Shselasky} 324246145Shselasky 325246145Shselasky/*------------------------------------------------------------------------* 326246145Shselasky * Implementation of device API 327246145Shselasky *------------------------------------------------------------------------*/ 328246145Shselasky 329246145Shselaskystatic const char unknown_string[] = { "unknown" }; 330246145Shselasky 331246145Shselaskystatic TAILQ_HEAD(, module_data) module_head = 332246145Shselasky TAILQ_HEAD_INITIALIZER(module_head); 333246145Shselasky 334246145Shselaskystatic uint8_t 335246145Shselaskydevclass_equal(const char *a, const char *b) 336246145Shselasky{ 337246145Shselasky char ta, tb; 338246145Shselasky 339246145Shselasky if (a == b) 340246145Shselasky return (1); 341246145Shselasky 342246145Shselasky while (1) { 343246145Shselasky ta = *a; 344246145Shselasky tb = *b; 345246145Shselasky if (ta != tb) 346246145Shselasky return (0); 347246145Shselasky if (ta == 0) 348246145Shselasky break; 349246145Shselasky a++; 350246145Shselasky b++; 351246145Shselasky } 352246145Shselasky return (1); 353246145Shselasky} 354246145Shselasky 355246145Shselaskyint 356246145Shselaskybus_generic_resume(device_t dev) 357246145Shselasky{ 358246145Shselasky return (0); 359246145Shselasky} 360246145Shselasky 361246145Shselaskyint 362246145Shselaskybus_generic_shutdown(device_t dev) 363246145Shselasky{ 364246145Shselasky return (0); 365246145Shselasky} 366246145Shselasky 367246145Shselaskyint 368246145Shselaskybus_generic_suspend(device_t dev) 369246145Shselasky{ 370246145Shselasky return (0); 371246145Shselasky} 372246145Shselasky 373246145Shselaskyint 374246145Shselaskybus_generic_print_child(device_t dev, device_t child) 375246145Shselasky{ 376246145Shselasky return (0); 377246145Shselasky} 378246145Shselasky 379246145Shselaskyvoid 380246145Shselaskybus_generic_driver_added(device_t dev, driver_t *driver) 381246145Shselasky{ 382246145Shselasky return; 383246145Shselasky} 384246145Shselasky 385246145Shselaskydevice_t 386246145Shselaskydevice_get_parent(device_t dev) 387246145Shselasky{ 388246145Shselasky return (dev ? dev->dev_parent : NULL); 389246145Shselasky} 390246145Shselasky 391246145Shselaskyvoid 392266396Shselaskydevice_set_interrupt(device_t dev, driver_filter_t *filter, 393266396Shselasky driver_intr_t *fn, void *arg) 394246145Shselasky{ 395266396Shselasky dev->dev_irq_filter = filter; 396246145Shselasky dev->dev_irq_fn = fn; 397246145Shselasky dev->dev_irq_arg = arg; 398246145Shselasky} 399246145Shselasky 400246145Shselaskyvoid 401246145Shselaskydevice_run_interrupts(device_t parent) 402246145Shselasky{ 403246145Shselasky device_t child; 404246145Shselasky 405246145Shselasky if (parent == NULL) 406246145Shselasky return; 407246145Shselasky 408246145Shselasky TAILQ_FOREACH(child, &parent->dev_children, dev_link) { 409266396Shselasky int status; 410266396Shselasky if (child->dev_irq_filter != NULL) 411266396Shselasky status = child->dev_irq_filter(child->dev_irq_arg); 412266396Shselasky else 413266396Shselasky status = FILTER_SCHEDULE_THREAD; 414266396Shselasky 415266396Shselasky if (status == FILTER_SCHEDULE_THREAD) { 416266396Shselasky if (child->dev_irq_fn != NULL) 417266396Shselasky (child->dev_irq_fn) (child->dev_irq_arg); 418266396Shselasky } 419246145Shselasky } 420246145Shselasky} 421246145Shselasky 422246145Shselaskyvoid 423246145Shselaskydevice_set_ivars(device_t dev, void *ivars) 424246145Shselasky{ 425246145Shselasky dev->dev_aux = ivars; 426246145Shselasky} 427246145Shselasky 428246145Shselaskyvoid * 429246145Shselaskydevice_get_ivars(device_t dev) 430246145Shselasky{ 431246145Shselasky return (dev ? dev->dev_aux : NULL); 432246145Shselasky} 433246145Shselasky 434246145Shselaskyint 435246145Shselaskydevice_get_unit(device_t dev) 436246145Shselasky{ 437246145Shselasky return (dev ? dev->dev_unit : 0); 438246145Shselasky} 439246145Shselasky 440246145Shselaskyint 441246145Shselaskybus_generic_detach(device_t dev) 442246145Shselasky{ 443246145Shselasky device_t child; 444246145Shselasky int error; 445246145Shselasky 446246145Shselasky if (!dev->dev_attached) 447246145Shselasky return (EBUSY); 448246145Shselasky 449246145Shselasky TAILQ_FOREACH(child, &dev->dev_children, dev_link) { 450246145Shselasky if ((error = device_detach(child)) != 0) 451246145Shselasky return (error); 452246145Shselasky } 453246145Shselasky return (0); 454246145Shselasky} 455246145Shselasky 456246145Shselaskyconst char * 457246145Shselaskydevice_get_nameunit(device_t dev) 458246145Shselasky{ 459246145Shselasky if (dev && dev->dev_nameunit[0]) 460246145Shselasky return (dev->dev_nameunit); 461246145Shselasky 462246145Shselasky return (unknown_string); 463246145Shselasky} 464246145Shselasky 465246145Shselaskystatic uint8_t 466246145Shselaskydevclass_create(devclass_t *dc_pp) 467246145Shselasky{ 468246145Shselasky if (dc_pp == NULL) { 469246145Shselasky return (1); 470246145Shselasky } 471246145Shselasky if (dc_pp[0] == NULL) { 472246145Shselasky dc_pp[0] = malloc(sizeof(**(dc_pp)), 473246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 474246145Shselasky 475246145Shselasky if (dc_pp[0] == NULL) { 476246145Shselasky return (1); 477246145Shselasky } 478246145Shselasky } 479246145Shselasky return (0); 480246145Shselasky} 481246145Shselasky 482246145Shselaskystatic const struct module_data * 483246145Shselaskydevclass_find_create(const char *classname) 484246145Shselasky{ 485246145Shselasky const struct module_data *mod; 486246145Shselasky 487246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 488246145Shselasky if (devclass_equal(mod->mod_name, classname)) { 489246145Shselasky if (devclass_create(mod->devclass_pp)) { 490246145Shselasky continue; 491246145Shselasky } 492246145Shselasky return (mod); 493246145Shselasky } 494246145Shselasky } 495246145Shselasky return (NULL); 496246145Shselasky} 497246145Shselasky 498246145Shselaskystatic uint8_t 499246145Shselaskydevclass_add_device(const struct module_data *mod, device_t dev) 500246145Shselasky{ 501246145Shselasky device_t *pp_dev; 502246145Shselasky device_t *end; 503246145Shselasky uint8_t unit; 504246145Shselasky 505246145Shselasky pp_dev = mod->devclass_pp[0]->dev_list; 506246145Shselasky end = pp_dev + DEVCLASS_MAXUNIT; 507246145Shselasky unit = 0; 508246145Shselasky 509246145Shselasky while (pp_dev != end) { 510246145Shselasky if (*pp_dev == NULL) { 511246145Shselasky *pp_dev = dev; 512246145Shselasky dev->dev_unit = unit; 513246145Shselasky dev->dev_module = mod; 514246145Shselasky snprintf(dev->dev_nameunit, 515246145Shselasky sizeof(dev->dev_nameunit), 516246145Shselasky "%s%d", device_get_name(dev), unit); 517246145Shselasky return (0); 518246145Shselasky } 519246145Shselasky pp_dev++; 520246145Shselasky unit++; 521246145Shselasky } 522246145Shselasky DPRINTF("Could not add device to devclass.\n"); 523246145Shselasky return (1); 524246145Shselasky} 525246145Shselasky 526246145Shselaskystatic void 527246145Shselaskydevclass_delete_device(const struct module_data *mod, device_t dev) 528246145Shselasky{ 529246145Shselasky if (mod == NULL) { 530246145Shselasky return; 531246145Shselasky } 532246145Shselasky mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL; 533246145Shselasky dev->dev_module = NULL; 534246145Shselasky} 535246145Shselasky 536246145Shselaskystatic device_t 537246145Shselaskymake_device(device_t parent, const char *name) 538246145Shselasky{ 539246145Shselasky device_t dev = NULL; 540246145Shselasky const struct module_data *mod = NULL; 541246145Shselasky 542246145Shselasky if (name) { 543246145Shselasky 544246145Shselasky mod = devclass_find_create(name); 545246145Shselasky 546246145Shselasky if (!mod) { 547246145Shselasky 548246145Shselasky DPRINTF("%s:%d:%s: can't find device " 549246145Shselasky "class %s\n", __FILE__, __LINE__, 550246145Shselasky __FUNCTION__, name); 551246145Shselasky 552246145Shselasky goto done; 553246145Shselasky } 554246145Shselasky } 555246145Shselasky dev = malloc(sizeof(*dev), 556246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 557246145Shselasky 558246145Shselasky if (dev == NULL) 559246145Shselasky goto done; 560246145Shselasky 561246145Shselasky dev->dev_parent = parent; 562246145Shselasky TAILQ_INIT(&dev->dev_children); 563246145Shselasky 564246145Shselasky if (name) { 565246145Shselasky dev->dev_fixed_class = 1; 566246145Shselasky if (devclass_add_device(mod, dev)) { 567246145Shselasky goto error; 568246145Shselasky } 569246145Shselasky } 570246145Shselaskydone: 571246145Shselasky return (dev); 572246145Shselasky 573246145Shselaskyerror: 574246145Shselasky if (dev) { 575246145Shselasky free(dev, M_DEVBUF); 576246145Shselasky } 577246145Shselasky return (NULL); 578246145Shselasky} 579246145Shselasky 580246145Shselaskydevice_t 581246145Shselaskydevice_add_child(device_t dev, const char *name, int unit) 582246145Shselasky{ 583246145Shselasky device_t child; 584246145Shselasky 585246145Shselasky if (unit != -1) { 586246145Shselasky device_printf(dev, "Unit is not -1\n"); 587246145Shselasky } 588246145Shselasky child = make_device(dev, name); 589246145Shselasky if (child == NULL) { 590246145Shselasky device_printf(dev, "Could not add child '%s'\n", name); 591246145Shselasky goto done; 592246145Shselasky } 593246145Shselasky if (dev == NULL) { 594246145Shselasky /* no parent */ 595246145Shselasky goto done; 596246145Shselasky } 597246145Shselasky TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link); 598246145Shselaskydone: 599246145Shselasky return (child); 600246145Shselasky} 601246145Shselasky 602246145Shselaskyint 603246145Shselaskydevice_delete_child(device_t dev, device_t child) 604246145Shselasky{ 605246145Shselasky int error = 0; 606246145Shselasky device_t grandchild; 607246145Shselasky 608246145Shselasky /* remove children first */ 609246145Shselasky 610246145Shselasky while ((grandchild = TAILQ_FIRST(&child->dev_children))) { 611246145Shselasky error = device_delete_child(child, grandchild); 612246145Shselasky if (error) { 613246145Shselasky device_printf(dev, "Error deleting child!\n"); 614246145Shselasky goto done; 615246145Shselasky } 616246145Shselasky } 617246145Shselasky 618246145Shselasky error = device_detach(child); 619246145Shselasky 620246145Shselasky if (error) 621246145Shselasky goto done; 622246145Shselasky 623246145Shselasky devclass_delete_device(child->dev_module, child); 624246145Shselasky 625246145Shselasky if (dev != NULL) { 626246145Shselasky /* remove child from parent */ 627246145Shselasky TAILQ_REMOVE(&dev->dev_children, child, dev_link); 628246145Shselasky } 629246145Shselasky free(child, M_DEVBUF); 630246145Shselasky 631246145Shselaskydone: 632246145Shselasky return (error); 633246145Shselasky} 634246145Shselasky 635246145Shselaskyint 636246145Shselaskydevice_delete_children(device_t dev) 637246145Shselasky{ 638246145Shselasky device_t child; 639246145Shselasky int error = 0; 640246145Shselasky 641246145Shselasky while ((child = TAILQ_FIRST(&dev->dev_children))) { 642246145Shselasky error = device_delete_child(dev, child); 643246145Shselasky if (error) { 644246145Shselasky device_printf(dev, "Error deleting child!\n"); 645246145Shselasky break; 646246145Shselasky } 647246145Shselasky } 648246145Shselasky return (error); 649246145Shselasky} 650246145Shselasky 651246145Shselaskyvoid 652246145Shselaskydevice_quiet(device_t dev) 653246145Shselasky{ 654246145Shselasky dev->dev_quiet = 1; 655246145Shselasky} 656246145Shselasky 657246145Shselaskyconst char * 658246145Shselaskydevice_get_desc(device_t dev) 659246145Shselasky{ 660246145Shselasky if (dev) 661246145Shselasky return &(dev->dev_desc[0]); 662246145Shselasky return (unknown_string); 663246145Shselasky} 664246145Shselasky 665246145Shselaskystatic int 666246145Shselaskydefault_method(void) 667246145Shselasky{ 668246145Shselasky /* do nothing */ 669246145Shselasky DPRINTF("Default method called\n"); 670246145Shselasky return (0); 671246145Shselasky} 672246145Shselasky 673246145Shselaskyvoid * 674246145Shselaskydevice_get_method(device_t dev, const char *what) 675246145Shselasky{ 676246145Shselasky const struct device_method *mtod; 677246145Shselasky 678246145Shselasky mtod = dev->dev_module->driver->methods; 679246145Shselasky while (mtod->func != NULL) { 680246145Shselasky if (devclass_equal(mtod->desc, what)) { 681246145Shselasky return (mtod->func); 682246145Shselasky } 683246145Shselasky mtod++; 684246145Shselasky } 685246145Shselasky return ((void *)&default_method); 686246145Shselasky} 687246145Shselasky 688246145Shselaskyconst char * 689246145Shselaskydevice_get_name(device_t dev) 690246145Shselasky{ 691246145Shselasky if (dev == NULL) 692246145Shselasky return (unknown_string); 693246145Shselasky 694246145Shselasky return (dev->dev_module->driver->name); 695246145Shselasky} 696246145Shselasky 697246145Shselaskystatic int 698246145Shselaskydevice_allocate_softc(device_t dev) 699246145Shselasky{ 700246145Shselasky const struct module_data *mod; 701246145Shselasky 702246145Shselasky mod = dev->dev_module; 703246145Shselasky 704246145Shselasky if ((dev->dev_softc_alloc == 0) && 705246145Shselasky (mod->driver->size != 0)) { 706246145Shselasky dev->dev_sc = malloc(mod->driver->size, 707246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 708246145Shselasky 709246145Shselasky if (dev->dev_sc == NULL) 710246145Shselasky return (ENOMEM); 711246145Shselasky 712246145Shselasky dev->dev_softc_alloc = 1; 713246145Shselasky } 714246145Shselasky return (0); 715246145Shselasky} 716246145Shselasky 717246145Shselaskyint 718246145Shselaskydevice_probe_and_attach(device_t dev) 719246145Shselasky{ 720246145Shselasky const struct module_data *mod; 721246145Shselasky const char *bus_name_parent; 722246145Shselasky 723246145Shselasky bus_name_parent = device_get_name(device_get_parent(dev)); 724246145Shselasky 725246145Shselasky if (dev->dev_attached) 726246145Shselasky return (0); /* fail-safe */ 727246145Shselasky 728246145Shselasky if (dev->dev_fixed_class) { 729246145Shselasky 730246145Shselasky mod = dev->dev_module; 731246145Shselasky 732246145Shselasky if (DEVICE_PROBE(dev) <= 0) { 733246145Shselasky 734246145Shselasky if (device_allocate_softc(dev) == 0) { 735246145Shselasky 736246145Shselasky if (DEVICE_ATTACH(dev) == 0) { 737246145Shselasky /* success */ 738246145Shselasky dev->dev_attached = 1; 739246145Shselasky return (0); 740246145Shselasky } 741246145Shselasky } 742246145Shselasky } 743246145Shselasky device_detach(dev); 744246145Shselasky 745246145Shselasky goto error; 746246145Shselasky } 747246145Shselasky /* 748246145Shselasky * Else find a module for our device, if any 749246145Shselasky */ 750246145Shselasky 751246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 752246145Shselasky if (devclass_equal(mod->bus_name, bus_name_parent)) { 753246145Shselasky if (devclass_create(mod->devclass_pp)) { 754246145Shselasky continue; 755246145Shselasky } 756246145Shselasky if (devclass_add_device(mod, dev)) { 757246145Shselasky continue; 758246145Shselasky } 759246145Shselasky if (DEVICE_PROBE(dev) <= 0) { 760246145Shselasky 761246145Shselasky if (device_allocate_softc(dev) == 0) { 762246145Shselasky 763246145Shselasky if (DEVICE_ATTACH(dev) == 0) { 764246145Shselasky /* success */ 765246145Shselasky dev->dev_attached = 1; 766246145Shselasky return (0); 767246145Shselasky } 768246145Shselasky } 769246145Shselasky } 770246145Shselasky /* else try next driver */ 771246145Shselasky 772246145Shselasky device_detach(dev); 773246145Shselasky } 774246145Shselasky } 775246145Shselasky 776246145Shselaskyerror: 777246145Shselasky return (ENODEV); 778246145Shselasky} 779246145Shselasky 780246145Shselaskyint 781246145Shselaskydevice_detach(device_t dev) 782246145Shselasky{ 783246145Shselasky const struct module_data *mod = dev->dev_module; 784246145Shselasky int error; 785246145Shselasky 786246145Shselasky if (dev->dev_attached) { 787246145Shselasky 788246145Shselasky error = DEVICE_DETACH(dev); 789246145Shselasky if (error) { 790246145Shselasky return error; 791246145Shselasky } 792246145Shselasky dev->dev_attached = 0; 793246145Shselasky } 794246145Shselasky device_set_softc(dev, NULL); 795246145Shselasky 796246145Shselasky if (dev->dev_fixed_class == 0) 797246145Shselasky devclass_delete_device(mod, dev); 798246145Shselasky 799246145Shselasky return (0); 800246145Shselasky} 801246145Shselasky 802246145Shselaskyvoid 803246145Shselaskydevice_set_softc(device_t dev, void *softc) 804246145Shselasky{ 805246145Shselasky if (dev->dev_softc_alloc) { 806246145Shselasky free(dev->dev_sc, M_DEVBUF); 807246145Shselasky dev->dev_sc = NULL; 808246145Shselasky } 809246145Shselasky dev->dev_sc = softc; 810246145Shselasky dev->dev_softc_alloc = 0; 811246145Shselasky} 812246145Shselasky 813246145Shselaskyvoid * 814246145Shselaskydevice_get_softc(device_t dev) 815246145Shselasky{ 816246145Shselasky if (dev == NULL) 817246145Shselasky return (NULL); 818246145Shselasky 819246145Shselasky return (dev->dev_sc); 820246145Shselasky} 821246145Shselasky 822246145Shselaskyint 823246145Shselaskydevice_is_attached(device_t dev) 824246145Shselasky{ 825246145Shselasky return (dev->dev_attached); 826246145Shselasky} 827246145Shselasky 828246145Shselaskyvoid 829246145Shselaskydevice_set_desc(device_t dev, const char *desc) 830246145Shselasky{ 831246145Shselasky snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc); 832246145Shselasky} 833246145Shselasky 834246145Shselaskyvoid 835246145Shselaskydevice_set_desc_copy(device_t dev, const char *desc) 836246145Shselasky{ 837246145Shselasky device_set_desc(dev, desc); 838246145Shselasky} 839246145Shselasky 840246145Shselaskyvoid * 841246145Shselaskydevclass_get_softc(devclass_t dc, int unit) 842246145Shselasky{ 843246145Shselasky return (device_get_softc(devclass_get_device(dc, unit))); 844246145Shselasky} 845246145Shselasky 846246145Shselaskyint 847246145Shselaskydevclass_get_maxunit(devclass_t dc) 848246145Shselasky{ 849246145Shselasky int max_unit = 0; 850246145Shselasky 851246145Shselasky if (dc) { 852246145Shselasky max_unit = DEVCLASS_MAXUNIT; 853246145Shselasky while (max_unit--) { 854246145Shselasky if (dc->dev_list[max_unit]) { 855246145Shselasky break; 856246145Shselasky } 857246145Shselasky } 858246145Shselasky max_unit++; 859246145Shselasky } 860246145Shselasky return (max_unit); 861246145Shselasky} 862246145Shselasky 863246145Shselaskydevice_t 864246145Shselaskydevclass_get_device(devclass_t dc, int unit) 865246145Shselasky{ 866246145Shselasky return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ? 867246145Shselasky NULL : dc->dev_list[unit]); 868246145Shselasky} 869246145Shselasky 870246145Shselaskydevclass_t 871246145Shselaskydevclass_find(const char *classname) 872246145Shselasky{ 873246145Shselasky const struct module_data *mod; 874246145Shselasky 875246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 876246145Shselasky if (devclass_equal(mod->mod_name, classname)) 877246145Shselasky return (mod->devclass_pp[0]); 878246145Shselasky } 879246145Shselasky return (NULL); 880246145Shselasky} 881246145Shselasky 882246145Shselaskyvoid 883246145Shselaskymodule_register(void *data) 884246145Shselasky{ 885246145Shselasky struct module_data *mdata = data; 886246145Shselasky 887246145Shselasky TAILQ_INSERT_TAIL(&module_head, mdata, entry); 888246145Shselasky} 889246145Shselasky 890246145Shselasky/*------------------------------------------------------------------------* 891246145Shselasky * System startup 892246145Shselasky *------------------------------------------------------------------------*/ 893246145Shselasky 894246145Shselaskystatic void 895246145Shselaskysysinit_run(const void **ppdata) 896246145Shselasky{ 897246145Shselasky const struct sysinit *psys; 898246145Shselasky 899246145Shselasky while ((psys = *ppdata) != NULL) { 900246145Shselasky (psys->func) (psys->data); 901246145Shselasky ppdata++; 902246145Shselasky } 903246145Shselasky} 904246145Shselasky 905246145Shselasky/*------------------------------------------------------------------------* 906246145Shselasky * USB process API 907246145Shselasky *------------------------------------------------------------------------*/ 908246145Shselasky 909246145Shselaskystatic int usb_do_process(struct usb_process *); 910246145Shselaskystatic int usb_proc_level = -1; 911246145Shselaskystatic struct mtx usb_proc_mtx; 912246145Shselasky 913246145Shselaskyvoid 914246145Shselaskyusb_idle(void) 915246145Shselasky{ 916246145Shselasky int old_level = usb_proc_level; 917246145Shselasky int old_giant = Giant.owned; 918246145Shselasky int worked; 919246145Shselasky 920246145Shselasky device_run_interrupts(usb_pci_root); 921246145Shselasky 922246145Shselasky do { 923246145Shselasky worked = 0; 924246145Shselasky Giant.owned = 0; 925246145Shselasky 926246145Shselasky while (++usb_proc_level < USB_PROC_MAX) 927246145Shselasky worked |= usb_do_process(usb_process + usb_proc_level); 928246145Shselasky 929246145Shselasky usb_proc_level = old_level; 930246145Shselasky Giant.owned = old_giant; 931246145Shselasky 932246145Shselasky } while (worked); 933246145Shselasky} 934246145Shselasky 935246145Shselaskyvoid 936246145Shselaskyusb_init(void) 937246145Shselasky{ 938246145Shselasky sysinit_run(sysinit_data); 939246145Shselasky} 940246145Shselasky 941246145Shselaskyvoid 942246145Shselaskyusb_uninit(void) 943246145Shselasky{ 944246145Shselasky sysinit_run(sysuninit_data); 945246145Shselasky} 946246145Shselasky 947246145Shselaskystatic void 948246145Shselaskyusb_process_init_sub(struct usb_process *up) 949246145Shselasky{ 950246145Shselasky TAILQ_INIT(&up->up_qhead); 951246145Shselasky 952246145Shselasky cv_init(&up->up_cv, "-"); 953246145Shselasky cv_init(&up->up_drain, "usbdrain"); 954246145Shselasky 955246145Shselasky up->up_mtx = &usb_proc_mtx; 956246145Shselasky} 957246145Shselasky 958246145Shselaskystatic void 959246145Shselaskyusb_process_init(void *arg) 960246145Shselasky{ 961246145Shselasky uint8_t x; 962246145Shselasky 963246145Shselasky mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE); 964246145Shselasky 965246145Shselasky for (x = 0; x != USB_PROC_MAX; x++) 966246145Shselasky usb_process_init_sub(&usb_process[x]); 967246145Shselasky 968246145Shselasky} 969246145ShselaskySYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL); 970246145Shselasky 971246145Shselaskystatic int 972246145Shselaskyusb_do_process(struct usb_process *up) 973246145Shselasky{ 974246145Shselasky struct usb_proc_msg *pm; 975246145Shselasky int worked = 0; 976246145Shselasky 977246145Shselasky mtx_lock(&usb_proc_mtx); 978246145Shselasky 979246145Shselaskyrepeat: 980246145Shselasky pm = TAILQ_FIRST(&up->up_qhead); 981246145Shselasky 982246145Shselasky if (pm != NULL) { 983246145Shselasky 984246145Shselasky worked = 1; 985246145Shselasky 986246145Shselasky (pm->pm_callback) (pm); 987246145Shselasky 988246145Shselasky if (pm == TAILQ_FIRST(&up->up_qhead)) { 989246145Shselasky /* nothing changed */ 990246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); 991246145Shselasky pm->pm_qentry.tqe_prev = NULL; 992246145Shselasky } 993246145Shselasky goto repeat; 994246145Shselasky } 995246145Shselasky mtx_unlock(&usb_proc_mtx); 996246145Shselasky 997246145Shselasky return (worked); 998246145Shselasky} 999246145Shselasky 1000246145Shselaskyvoid * 1001246145Shselaskyusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1) 1002246145Shselasky{ 1003246145Shselasky struct usb_proc_msg *pm0 = _pm0; 1004246145Shselasky struct usb_proc_msg *pm1 = _pm1; 1005246145Shselasky struct usb_proc_msg *pm2; 1006246145Shselasky usb_size_t d; 1007246145Shselasky uint8_t t; 1008246145Shselasky 1009246145Shselasky t = 0; 1010246145Shselasky 1011246145Shselasky if (pm0->pm_qentry.tqe_prev) { 1012246145Shselasky t |= 1; 1013246145Shselasky } 1014246145Shselasky if (pm1->pm_qentry.tqe_prev) { 1015246145Shselasky t |= 2; 1016246145Shselasky } 1017246145Shselasky if (t == 0) { 1018246145Shselasky /* 1019246145Shselasky * No entries are queued. Queue "pm0" and use the existing 1020246145Shselasky * message number. 1021246145Shselasky */ 1022246145Shselasky pm2 = pm0; 1023246145Shselasky } else if (t == 1) { 1024246145Shselasky /* Check if we need to increment the message number. */ 1025246145Shselasky if (pm0->pm_num == up->up_msg_num) { 1026246145Shselasky up->up_msg_num++; 1027246145Shselasky } 1028246145Shselasky pm2 = pm1; 1029246145Shselasky } else if (t == 2) { 1030246145Shselasky /* Check if we need to increment the message number. */ 1031246145Shselasky if (pm1->pm_num == up->up_msg_num) { 1032246145Shselasky up->up_msg_num++; 1033246145Shselasky } 1034246145Shselasky pm2 = pm0; 1035246145Shselasky } else if (t == 3) { 1036246145Shselasky /* 1037246145Shselasky * Both entries are queued. Re-queue the entry closest to 1038246145Shselasky * the end. 1039246145Shselasky */ 1040246145Shselasky d = (pm1->pm_num - pm0->pm_num); 1041246145Shselasky 1042246145Shselasky /* Check sign after subtraction */ 1043246145Shselasky if (d & 0x80000000) { 1044246145Shselasky pm2 = pm0; 1045246145Shselasky } else { 1046246145Shselasky pm2 = pm1; 1047246145Shselasky } 1048246145Shselasky 1049246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry); 1050246145Shselasky } else { 1051246145Shselasky pm2 = NULL; /* panic - should not happen */ 1052246145Shselasky } 1053246145Shselasky 1054246145Shselasky /* Put message last on queue */ 1055246145Shselasky 1056246145Shselasky pm2->pm_num = up->up_msg_num; 1057246145Shselasky TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry); 1058246145Shselasky 1059246145Shselasky return (pm2); 1060246145Shselasky} 1061246145Shselasky 1062246145Shselasky/*------------------------------------------------------------------------* 1063246145Shselasky * usb_proc_is_gone 1064246145Shselasky * 1065246145Shselasky * Return values: 1066246145Shselasky * 0: USB process is running 1067246145Shselasky * Else: USB process is tearing down 1068246145Shselasky *------------------------------------------------------------------------*/ 1069246145Shselaskyuint8_t 1070246145Shselaskyusb_proc_is_gone(struct usb_process *up) 1071246145Shselasky{ 1072246145Shselasky return (0); 1073246145Shselasky} 1074246145Shselasky 1075246145Shselasky/*------------------------------------------------------------------------* 1076246145Shselasky * usb_proc_mwait 1077246145Shselasky * 1078246145Shselasky * This function will return when the USB process message pointed to 1079246145Shselasky * by "pm" is no longer on a queue. This function must be called 1080246145Shselasky * having "usb_proc_mtx" locked. 1081246145Shselasky *------------------------------------------------------------------------*/ 1082246145Shselaskyvoid 1083246145Shselaskyusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1) 1084246145Shselasky{ 1085246145Shselasky struct usb_proc_msg *pm0 = _pm0; 1086246145Shselasky struct usb_proc_msg *pm1 = _pm1; 1087246145Shselasky 1088246145Shselasky /* Just remove the messages from the queue. */ 1089246145Shselasky if (pm0->pm_qentry.tqe_prev) { 1090246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry); 1091246145Shselasky pm0->pm_qentry.tqe_prev = NULL; 1092246145Shselasky } 1093246145Shselasky if (pm1->pm_qentry.tqe_prev) { 1094246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry); 1095246145Shselasky pm1->pm_qentry.tqe_prev = NULL; 1096246145Shselasky } 1097246145Shselasky} 1098246145Shselasky 1099246145Shselasky/*------------------------------------------------------------------------* 1100246145Shselasky * SYSTEM attach 1101246145Shselasky *------------------------------------------------------------------------*/ 1102246145Shselasky 1103266882Shselasky#ifdef USB_PCI_PROBE_LIST 1104246145Shselaskystatic device_method_t pci_methods[] = { 1105246145Shselasky DEVMETHOD_END 1106246145Shselasky}; 1107246145Shselasky 1108246145Shselaskystatic driver_t pci_driver = { 1109246145Shselasky .name = "pci", 1110246145Shselasky .methods = pci_methods, 1111246145Shselasky}; 1112246145Shselasky 1113246145Shselaskystatic devclass_t pci_devclass; 1114246145Shselasky 1115246145ShselaskyDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0); 1116246145Shselasky 1117246145Shselaskystatic const char *usb_pci_devices[] = { 1118266882Shselasky USB_PCI_PROBE_LIST 1119246145Shselasky}; 1120246145Shselasky 1121246145Shselasky#define USB_PCI_USB_MAX (sizeof(usb_pci_devices) / sizeof(void *)) 1122246145Shselasky 1123246145Shselaskystatic device_t usb_pci_dev[USB_PCI_USB_MAX]; 1124246145Shselasky 1125246145Shselaskystatic void 1126246145Shselaskyusb_pci_mod_load(void *arg) 1127246145Shselasky{ 1128246145Shselasky uint32_t x; 1129246145Shselasky 1130246145Shselasky usb_pci_root = device_add_child(NULL, "pci", -1); 1131246145Shselasky if (usb_pci_root == NULL) 1132246145Shselasky return; 1133246145Shselasky 1134246145Shselasky for (x = 0; x != USB_PCI_USB_MAX; x++) { 1135246145Shselasky usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1); 1136246145Shselasky if (usb_pci_dev[x] == NULL) 1137246145Shselasky continue; 1138246145Shselasky if (device_probe_and_attach(usb_pci_dev[x])) { 1139246145Shselasky device_printf(usb_pci_dev[x], 1140246145Shselasky "WARNING: Probe and attach failed!\n"); 1141246145Shselasky } 1142246145Shselasky } 1143246145Shselasky} 1144246145ShselaskySYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0); 1145246145Shselasky 1146246145Shselaskystatic void 1147246145Shselaskyusb_pci_mod_unload(void *arg) 1148246145Shselasky{ 1149246145Shselasky uint32_t x; 1150246145Shselasky 1151246145Shselasky for (x = 0; x != USB_PCI_USB_MAX; x++) { 1152246145Shselasky if (usb_pci_dev[x]) { 1153246145Shselasky device_detach(usb_pci_dev[x]); 1154246145Shselasky device_delete_child(usb_pci_root, usb_pci_dev[x]); 1155246145Shselasky } 1156246145Shselasky } 1157246145Shselasky if (usb_pci_root) 1158246145Shselasky device_delete_child(NULL, usb_pci_root); 1159246145Shselasky} 1160246145ShselaskySYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0); 1161266882Shselasky#endif 1162246145Shselasky 1163246145Shselasky/*------------------------------------------------------------------------* 1164246145Shselasky * MALLOC API 1165246145Shselasky *------------------------------------------------------------------------*/ 1166246145Shselasky 1167266882Shselasky#ifndef HAVE_MALLOC 1168246145Shselasky#define USB_POOL_ALIGN 8 1169246145Shselasky 1170246145Shselaskystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN); 1171246145Shselaskystatic uint32_t usb_pool_rem = USB_POOL_SIZE; 1172246145Shselaskystatic uint32_t usb_pool_entries; 1173246145Shselasky 1174246145Shselaskystruct malloc_hdr { 1175246145Shselasky TAILQ_ENTRY(malloc_hdr) entry; 1176246145Shselasky uint32_t size; 1177246145Shselasky} __aligned(USB_POOL_ALIGN); 1178246145Shselasky 1179246145Shselaskystatic TAILQ_HEAD(, malloc_hdr) malloc_head = 1180246145Shselasky TAILQ_HEAD_INITIALIZER(malloc_head); 1181246145Shselasky 1182246145Shselaskyvoid * 1183246145Shselaskyusb_malloc(unsigned long size) 1184246145Shselasky{ 1185246145Shselasky struct malloc_hdr *hdr; 1186246145Shselasky 1187246145Shselasky size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1); 1188246145Shselasky size += sizeof(struct malloc_hdr); 1189246145Shselasky 1190246145Shselasky TAILQ_FOREACH(hdr, &malloc_head, entry) { 1191246145Shselasky if (hdr->size == size) 1192246145Shselasky break; 1193246145Shselasky } 1194246145Shselasky 1195246145Shselasky if (hdr) { 1196266882Shselasky DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1197246145Shselasky (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1198246145Shselasky 1199246145Shselasky TAILQ_REMOVE(&malloc_head, hdr, entry); 1200246145Shselasky memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1201246145Shselasky return (hdr + 1); 1202246145Shselasky } 1203246145Shselasky if (usb_pool_rem >= size) { 1204246145Shselasky hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem); 1205246145Shselasky hdr->size = size; 1206246145Shselasky 1207246145Shselasky usb_pool_rem -= size; 1208246145Shselasky usb_pool_entries++; 1209246145Shselasky 1210266882Shselasky DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1211246145Shselasky (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1212246145Shselasky 1213246145Shselasky memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1214246145Shselasky return (hdr + 1); 1215246145Shselasky } 1216246145Shselasky return (NULL); 1217246145Shselasky} 1218246145Shselasky 1219246145Shselaskyvoid 1220246145Shselaskyusb_free(void *arg) 1221246145Shselasky{ 1222246145Shselasky struct malloc_hdr *hdr; 1223246145Shselasky 1224246145Shselasky if (arg == NULL) 1225246145Shselasky return; 1226246145Shselasky 1227246145Shselasky hdr = arg; 1228246145Shselasky hdr--; 1229246145Shselasky 1230246145Shselasky TAILQ_INSERT_TAIL(&malloc_head, hdr, entry); 1231246145Shselasky} 1232266882Shselasky#endif 1233246145Shselasky 1234246145Shselaskychar * 1235246145Shselaskyusb_strdup(const char *str) 1236246145Shselasky{ 1237246145Shselasky char *tmp; 1238246145Shselasky int len; 1239246145Shselasky 1240246145Shselasky len = 1 + strlen(str); 1241246145Shselasky 1242266882Shselasky tmp = malloc(len,XXX,XXX); 1243246145Shselasky if (tmp == NULL) 1244246145Shselasky return (NULL); 1245246145Shselasky 1246246145Shselasky memcpy(tmp, str, len); 1247246145Shselasky return (tmp); 1248246145Shselasky} 1249