1246145Shselasky/* $FreeBSD$ */ 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; 141246145Shselasky 142246145Shselasky if (cv->sleeping) 143246145Shselasky return (EWOULDBLOCK); /* not allowed */ 144246145Shselasky 145246145Shselasky cv->sleeping = 1; 146246145Shselasky 147246145Shselasky while (cv->sleeping) { 148246145Shselasky if (timo >= 0) { 149246145Shselasky delta = ticks - start; 150246145Shselasky if (delta >= timo || delta < 0) 151246145Shselasky break; 152246145Shselasky } 153246145Shselasky mtx_unlock(mtx); 154246145Shselasky 155246145Shselasky usb_idle(); 156246145Shselasky 157246145Shselasky mtx_lock(mtx); 158246145Shselasky } 159246145Shselasky 160246145Shselasky if (cv->sleeping) { 161246145Shselasky cv->sleeping = 0; 162246145Shselasky return (EWOULDBLOCK); /* not allowed */ 163246145Shselasky } 164246145Shselasky return (0); 165246145Shselasky} 166246145Shselasky 167246145Shselaskyvoid 168246145Shselaskycv_signal(struct cv *cv) 169246145Shselasky{ 170246145Shselasky cv->sleeping = 0; 171246145Shselasky} 172246145Shselasky 173246145Shselaskyvoid 174246145Shselaskycv_broadcast(struct cv *cv) 175246145Shselasky{ 176246145Shselasky cv->sleeping = 0; 177246145Shselasky} 178246145Shselasky 179246145Shselasky/*------------------------------------------------------------------------* 180246145Shselasky * Implementation of callout API 181246145Shselasky *------------------------------------------------------------------------*/ 182246145Shselasky 183246145Shselaskystatic void callout_proc_msg(struct usb_proc_msg *); 184246145Shselasky 185246145Shselaskyvolatile int ticks = 0; 186246145Shselasky 187246145Shselaskystatic LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout); 188246145Shselasky 189246145Shselaskystatic struct mtx mtx_callout; 190246145Shselaskystatic struct usb_proc_msg callout_msg[2]; 191246145Shselasky 192246145Shselaskystatic void 193246145Shselaskycallout_system_init(void *arg) 194246145Shselasky{ 195246145Shselasky mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE); 196246145Shselasky 197246145Shselasky callout_msg[0].pm_callback = &callout_proc_msg; 198246145Shselasky callout_msg[1].pm_callback = &callout_proc_msg; 199246145Shselasky} 200246145ShselaskySYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL); 201246145Shselasky 202246145Shselaskystatic void 203246145Shselaskycallout_callback(struct callout *c) 204246145Shselasky{ 205246145Shselasky mtx_lock(c->mtx); 206246145Shselasky 207246145Shselasky mtx_lock(&mtx_callout); 208246145Shselasky if (c->entry.le_prev != NULL) { 209246145Shselasky LIST_REMOVE(c, entry); 210246145Shselasky c->entry.le_prev = NULL; 211246145Shselasky } 212246145Shselasky mtx_unlock(&mtx_callout); 213246145Shselasky 214246145Shselasky if (c->func) 215246145Shselasky (c->func) (c->arg); 216246145Shselasky 217246145Shselasky if (!(c->flags & CALLOUT_RETURNUNLOCKED)) 218246145Shselasky mtx_unlock(c->mtx); 219246145Shselasky} 220246145Shselasky 221246145Shselaskyvoid 222246145Shselaskycallout_process(int timeout) 223246145Shselasky{ 224246145Shselasky ticks += timeout; 225246145Shselasky usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]); 226246145Shselasky} 227246145Shselasky 228246145Shselaskystatic void 229246145Shselaskycallout_proc_msg(struct usb_proc_msg *pmsg) 230246145Shselasky{ 231246145Shselasky struct callout *c; 232246145Shselasky int delta; 233246145Shselasky 234246145Shselaskyrepeat: 235246145Shselasky mtx_lock(&mtx_callout); 236246145Shselasky 237246145Shselasky LIST_FOREACH(c, &head_callout, entry) { 238246145Shselasky 239246145Shselasky delta = c->timeout - ticks; 240246145Shselasky if (delta < 0) { 241246145Shselasky mtx_unlock(&mtx_callout); 242246145Shselasky 243246145Shselasky callout_callback(c); 244246145Shselasky 245246145Shselasky goto repeat; 246246145Shselasky } 247246145Shselasky } 248246145Shselasky mtx_unlock(&mtx_callout); 249246145Shselasky} 250246145Shselasky 251246145Shselaskyvoid 252246145Shselaskycallout_init_mtx(struct callout *c, struct mtx *mtx, int flags) 253246145Shselasky{ 254246145Shselasky memset(c, 0, sizeof(*c)); 255246145Shselasky 256246145Shselasky if (mtx == NULL) 257246145Shselasky mtx = &Giant; 258246145Shselasky 259246145Shselasky c->mtx = mtx; 260246145Shselasky c->flags = (flags & CALLOUT_RETURNUNLOCKED); 261246145Shselasky} 262246145Shselasky 263246145Shselaskyvoid 264246145Shselaskycallout_reset(struct callout *c, int to_ticks, 265246145Shselasky void (*func) (void *), void *arg) 266246145Shselasky{ 267246145Shselasky callout_stop(c); 268246145Shselasky 269246145Shselasky c->func = func; 270246145Shselasky c->arg = arg; 271246145Shselasky c->timeout = ticks + to_ticks; 272246145Shselasky 273246145Shselasky mtx_lock(&mtx_callout); 274246145Shselasky LIST_INSERT_HEAD(&head_callout, c, entry); 275246145Shselasky mtx_unlock(&mtx_callout); 276246145Shselasky} 277246145Shselasky 278246145Shselaskyvoid 279246145Shselaskycallout_stop(struct callout *c) 280246145Shselasky{ 281246145Shselasky mtx_lock(&mtx_callout); 282246145Shselasky 283246145Shselasky if (c->entry.le_prev != NULL) { 284246145Shselasky LIST_REMOVE(c, entry); 285246145Shselasky c->entry.le_prev = NULL; 286246145Shselasky } 287246145Shselasky mtx_unlock(&mtx_callout); 288246145Shselasky 289246145Shselasky c->func = NULL; 290246145Shselasky c->arg = NULL; 291246145Shselasky} 292246145Shselasky 293246145Shselaskyvoid 294246145Shselaskycallout_drain(struct callout *c) 295246145Shselasky{ 296246145Shselasky if (c->mtx == NULL) 297246145Shselasky return; /* not initialised */ 298246145Shselasky 299246145Shselasky mtx_lock(c->mtx); 300246145Shselasky callout_stop(c); 301246145Shselasky mtx_unlock(c->mtx); 302246145Shselasky} 303246145Shselasky 304246145Shselaskyint 305246145Shselaskycallout_pending(struct callout *c) 306246145Shselasky{ 307246145Shselasky int retval; 308246145Shselasky 309246145Shselasky mtx_lock(&mtx_callout); 310246145Shselasky retval = (c->entry.le_prev != NULL); 311246145Shselasky mtx_unlock(&mtx_callout); 312246145Shselasky 313246145Shselasky return (retval); 314246145Shselasky} 315246145Shselasky 316246145Shselasky/*------------------------------------------------------------------------* 317246145Shselasky * Implementation of device API 318246145Shselasky *------------------------------------------------------------------------*/ 319246145Shselasky 320246145Shselaskystatic const char unknown_string[] = { "unknown" }; 321246145Shselasky 322246145Shselaskystatic TAILQ_HEAD(, module_data) module_head = 323246145Shselasky TAILQ_HEAD_INITIALIZER(module_head); 324246145Shselasky 325246145Shselaskystatic uint8_t 326246145Shselaskydevclass_equal(const char *a, const char *b) 327246145Shselasky{ 328246145Shselasky char ta, tb; 329246145Shselasky 330246145Shselasky if (a == b) 331246145Shselasky return (1); 332246145Shselasky 333246145Shselasky while (1) { 334246145Shselasky ta = *a; 335246145Shselasky tb = *b; 336246145Shselasky if (ta != tb) 337246145Shselasky return (0); 338246145Shselasky if (ta == 0) 339246145Shselasky break; 340246145Shselasky a++; 341246145Shselasky b++; 342246145Shselasky } 343246145Shselasky return (1); 344246145Shselasky} 345246145Shselasky 346246145Shselaskyint 347246145Shselaskybus_generic_resume(device_t dev) 348246145Shselasky{ 349246145Shselasky return (0); 350246145Shselasky} 351246145Shselasky 352246145Shselaskyint 353246145Shselaskybus_generic_shutdown(device_t dev) 354246145Shselasky{ 355246145Shselasky return (0); 356246145Shselasky} 357246145Shselasky 358246145Shselaskyint 359246145Shselaskybus_generic_suspend(device_t dev) 360246145Shselasky{ 361246145Shselasky return (0); 362246145Shselasky} 363246145Shselasky 364246145Shselaskyint 365246145Shselaskybus_generic_print_child(device_t dev, device_t child) 366246145Shselasky{ 367246145Shselasky return (0); 368246145Shselasky} 369246145Shselasky 370246145Shselaskyvoid 371246145Shselaskybus_generic_driver_added(device_t dev, driver_t *driver) 372246145Shselasky{ 373246145Shselasky return; 374246145Shselasky} 375246145Shselasky 376246145Shselaskydevice_t 377246145Shselaskydevice_get_parent(device_t dev) 378246145Shselasky{ 379246145Shselasky return (dev ? dev->dev_parent : NULL); 380246145Shselasky} 381246145Shselasky 382246145Shselaskyvoid 383246145Shselaskydevice_set_interrupt(device_t dev, intr_fn_t *fn, void *arg) 384246145Shselasky{ 385246145Shselasky dev->dev_irq_fn = fn; 386246145Shselasky dev->dev_irq_arg = arg; 387246145Shselasky} 388246145Shselasky 389246145Shselaskyvoid 390246145Shselaskydevice_run_interrupts(device_t parent) 391246145Shselasky{ 392246145Shselasky device_t child; 393246145Shselasky 394246145Shselasky if (parent == NULL) 395246145Shselasky return; 396246145Shselasky 397246145Shselasky TAILQ_FOREACH(child, &parent->dev_children, dev_link) { 398246145Shselasky if (child->dev_irq_fn != NULL) 399246145Shselasky (child->dev_irq_fn) (child->dev_irq_arg); 400246145Shselasky } 401246145Shselasky} 402246145Shselasky 403246145Shselaskyvoid 404246145Shselaskydevice_set_ivars(device_t dev, void *ivars) 405246145Shselasky{ 406246145Shselasky dev->dev_aux = ivars; 407246145Shselasky} 408246145Shselasky 409246145Shselaskyvoid * 410246145Shselaskydevice_get_ivars(device_t dev) 411246145Shselasky{ 412246145Shselasky return (dev ? dev->dev_aux : NULL); 413246145Shselasky} 414246145Shselasky 415246145Shselaskyint 416246145Shselaskydevice_get_unit(device_t dev) 417246145Shselasky{ 418246145Shselasky return (dev ? dev->dev_unit : 0); 419246145Shselasky} 420246145Shselasky 421246145Shselaskyint 422246145Shselaskybus_generic_detach(device_t dev) 423246145Shselasky{ 424246145Shselasky device_t child; 425246145Shselasky int error; 426246145Shselasky 427246145Shselasky if (!dev->dev_attached) 428246145Shselasky return (EBUSY); 429246145Shselasky 430246145Shselasky TAILQ_FOREACH(child, &dev->dev_children, dev_link) { 431246145Shselasky if ((error = device_detach(child)) != 0) 432246145Shselasky return (error); 433246145Shselasky } 434246145Shselasky return (0); 435246145Shselasky} 436246145Shselasky 437246145Shselaskyconst char * 438246145Shselaskydevice_get_nameunit(device_t dev) 439246145Shselasky{ 440246145Shselasky if (dev && dev->dev_nameunit[0]) 441246145Shselasky return (dev->dev_nameunit); 442246145Shselasky 443246145Shselasky return (unknown_string); 444246145Shselasky} 445246145Shselasky 446246145Shselaskystatic uint8_t 447246145Shselaskydevclass_create(devclass_t *dc_pp) 448246145Shselasky{ 449246145Shselasky if (dc_pp == NULL) { 450246145Shselasky return (1); 451246145Shselasky } 452246145Shselasky if (dc_pp[0] == NULL) { 453246145Shselasky dc_pp[0] = malloc(sizeof(**(dc_pp)), 454246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 455246145Shselasky 456246145Shselasky if (dc_pp[0] == NULL) { 457246145Shselasky return (1); 458246145Shselasky } 459246145Shselasky } 460246145Shselasky return (0); 461246145Shselasky} 462246145Shselasky 463246145Shselaskystatic const struct module_data * 464246145Shselaskydevclass_find_create(const char *classname) 465246145Shselasky{ 466246145Shselasky const struct module_data *mod; 467246145Shselasky 468246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 469246145Shselasky if (devclass_equal(mod->mod_name, classname)) { 470246145Shselasky if (devclass_create(mod->devclass_pp)) { 471246145Shselasky continue; 472246145Shselasky } 473246145Shselasky return (mod); 474246145Shselasky } 475246145Shselasky } 476246145Shselasky return (NULL); 477246145Shselasky} 478246145Shselasky 479246145Shselaskystatic uint8_t 480246145Shselaskydevclass_add_device(const struct module_data *mod, device_t dev) 481246145Shselasky{ 482246145Shselasky device_t *pp_dev; 483246145Shselasky device_t *end; 484246145Shselasky uint8_t unit; 485246145Shselasky 486246145Shselasky pp_dev = mod->devclass_pp[0]->dev_list; 487246145Shselasky end = pp_dev + DEVCLASS_MAXUNIT; 488246145Shselasky unit = 0; 489246145Shselasky 490246145Shselasky while (pp_dev != end) { 491246145Shselasky if (*pp_dev == NULL) { 492246145Shselasky *pp_dev = dev; 493246145Shselasky dev->dev_unit = unit; 494246145Shselasky dev->dev_module = mod; 495246145Shselasky snprintf(dev->dev_nameunit, 496246145Shselasky sizeof(dev->dev_nameunit), 497246145Shselasky "%s%d", device_get_name(dev), unit); 498246145Shselasky return (0); 499246145Shselasky } 500246145Shselasky pp_dev++; 501246145Shselasky unit++; 502246145Shselasky } 503246145Shselasky DPRINTF("Could not add device to devclass.\n"); 504246145Shselasky return (1); 505246145Shselasky} 506246145Shselasky 507246145Shselaskystatic void 508246145Shselaskydevclass_delete_device(const struct module_data *mod, device_t dev) 509246145Shselasky{ 510246145Shselasky if (mod == NULL) { 511246145Shselasky return; 512246145Shselasky } 513246145Shselasky mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL; 514246145Shselasky dev->dev_module = NULL; 515246145Shselasky} 516246145Shselasky 517246145Shselaskystatic device_t 518246145Shselaskymake_device(device_t parent, const char *name) 519246145Shselasky{ 520246145Shselasky device_t dev = NULL; 521246145Shselasky const struct module_data *mod = NULL; 522246145Shselasky 523246145Shselasky if (name) { 524246145Shselasky 525246145Shselasky mod = devclass_find_create(name); 526246145Shselasky 527246145Shselasky if (!mod) { 528246145Shselasky 529246145Shselasky DPRINTF("%s:%d:%s: can't find device " 530246145Shselasky "class %s\n", __FILE__, __LINE__, 531246145Shselasky __FUNCTION__, name); 532246145Shselasky 533246145Shselasky goto done; 534246145Shselasky } 535246145Shselasky } 536246145Shselasky dev = malloc(sizeof(*dev), 537246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 538246145Shselasky 539246145Shselasky if (dev == NULL) 540246145Shselasky goto done; 541246145Shselasky 542246145Shselasky dev->dev_parent = parent; 543246145Shselasky TAILQ_INIT(&dev->dev_children); 544246145Shselasky 545246145Shselasky if (name) { 546246145Shselasky dev->dev_fixed_class = 1; 547246145Shselasky if (devclass_add_device(mod, dev)) { 548246145Shselasky goto error; 549246145Shselasky } 550246145Shselasky } 551246145Shselaskydone: 552246145Shselasky return (dev); 553246145Shselasky 554246145Shselaskyerror: 555246145Shselasky if (dev) { 556246145Shselasky free(dev, M_DEVBUF); 557246145Shselasky } 558246145Shselasky return (NULL); 559246145Shselasky} 560246145Shselasky 561246145Shselaskydevice_t 562246145Shselaskydevice_add_child(device_t dev, const char *name, int unit) 563246145Shselasky{ 564246145Shselasky device_t child; 565246145Shselasky 566246145Shselasky if (unit != -1) { 567246145Shselasky device_printf(dev, "Unit is not -1\n"); 568246145Shselasky } 569246145Shselasky child = make_device(dev, name); 570246145Shselasky if (child == NULL) { 571246145Shselasky device_printf(dev, "Could not add child '%s'\n", name); 572246145Shselasky goto done; 573246145Shselasky } 574246145Shselasky if (dev == NULL) { 575246145Shselasky /* no parent */ 576246145Shselasky goto done; 577246145Shselasky } 578246145Shselasky TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link); 579246145Shselaskydone: 580246145Shselasky return (child); 581246145Shselasky} 582246145Shselasky 583246145Shselaskyint 584246145Shselaskydevice_delete_child(device_t dev, device_t child) 585246145Shselasky{ 586246145Shselasky int error = 0; 587246145Shselasky device_t grandchild; 588246145Shselasky 589246145Shselasky /* remove children first */ 590246145Shselasky 591246145Shselasky while ((grandchild = TAILQ_FIRST(&child->dev_children))) { 592246145Shselasky error = device_delete_child(child, grandchild); 593246145Shselasky if (error) { 594246145Shselasky device_printf(dev, "Error deleting child!\n"); 595246145Shselasky goto done; 596246145Shselasky } 597246145Shselasky } 598246145Shselasky 599246145Shselasky error = device_detach(child); 600246145Shselasky 601246145Shselasky if (error) 602246145Shselasky goto done; 603246145Shselasky 604246145Shselasky devclass_delete_device(child->dev_module, child); 605246145Shselasky 606246145Shselasky if (dev != NULL) { 607246145Shselasky /* remove child from parent */ 608246145Shselasky TAILQ_REMOVE(&dev->dev_children, child, dev_link); 609246145Shselasky } 610246145Shselasky free(child, M_DEVBUF); 611246145Shselasky 612246145Shselaskydone: 613246145Shselasky return (error); 614246145Shselasky} 615246145Shselasky 616246145Shselaskyint 617246145Shselaskydevice_delete_children(device_t dev) 618246145Shselasky{ 619246145Shselasky device_t child; 620246145Shselasky int error = 0; 621246145Shselasky 622246145Shselasky while ((child = TAILQ_FIRST(&dev->dev_children))) { 623246145Shselasky error = device_delete_child(dev, child); 624246145Shselasky if (error) { 625246145Shselasky device_printf(dev, "Error deleting child!\n"); 626246145Shselasky break; 627246145Shselasky } 628246145Shselasky } 629246145Shselasky return (error); 630246145Shselasky} 631246145Shselasky 632246145Shselaskyvoid 633246145Shselaskydevice_quiet(device_t dev) 634246145Shselasky{ 635246145Shselasky dev->dev_quiet = 1; 636246145Shselasky} 637246145Shselasky 638246145Shselaskyconst char * 639246145Shselaskydevice_get_desc(device_t dev) 640246145Shselasky{ 641246145Shselasky if (dev) 642246145Shselasky return &(dev->dev_desc[0]); 643246145Shselasky return (unknown_string); 644246145Shselasky} 645246145Shselasky 646246145Shselaskystatic int 647246145Shselaskydefault_method(void) 648246145Shselasky{ 649246145Shselasky /* do nothing */ 650246145Shselasky DPRINTF("Default method called\n"); 651246145Shselasky return (0); 652246145Shselasky} 653246145Shselasky 654246145Shselaskyvoid * 655246145Shselaskydevice_get_method(device_t dev, const char *what) 656246145Shselasky{ 657246145Shselasky const struct device_method *mtod; 658246145Shselasky 659246145Shselasky mtod = dev->dev_module->driver->methods; 660246145Shselasky while (mtod->func != NULL) { 661246145Shselasky if (devclass_equal(mtod->desc, what)) { 662246145Shselasky return (mtod->func); 663246145Shselasky } 664246145Shselasky mtod++; 665246145Shselasky } 666246145Shselasky return ((void *)&default_method); 667246145Shselasky} 668246145Shselasky 669246145Shselaskyconst char * 670246145Shselaskydevice_get_name(device_t dev) 671246145Shselasky{ 672246145Shselasky if (dev == NULL) 673246145Shselasky return (unknown_string); 674246145Shselasky 675246145Shselasky return (dev->dev_module->driver->name); 676246145Shselasky} 677246145Shselasky 678246145Shselaskystatic int 679246145Shselaskydevice_allocate_softc(device_t dev) 680246145Shselasky{ 681246145Shselasky const struct module_data *mod; 682246145Shselasky 683246145Shselasky mod = dev->dev_module; 684246145Shselasky 685246145Shselasky if ((dev->dev_softc_alloc == 0) && 686246145Shselasky (mod->driver->size != 0)) { 687246145Shselasky dev->dev_sc = malloc(mod->driver->size, 688246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 689246145Shselasky 690246145Shselasky if (dev->dev_sc == NULL) 691246145Shselasky return (ENOMEM); 692246145Shselasky 693246145Shselasky dev->dev_softc_alloc = 1; 694246145Shselasky } 695246145Shselasky return (0); 696246145Shselasky} 697246145Shselasky 698246145Shselaskyint 699246145Shselaskydevice_probe_and_attach(device_t dev) 700246145Shselasky{ 701246145Shselasky const struct module_data *mod; 702246145Shselasky const char *bus_name_parent; 703246145Shselasky 704246145Shselasky bus_name_parent = device_get_name(device_get_parent(dev)); 705246145Shselasky 706246145Shselasky if (dev->dev_attached) 707246145Shselasky return (0); /* fail-safe */ 708246145Shselasky 709246145Shselasky if (dev->dev_fixed_class) { 710246145Shselasky 711246145Shselasky mod = dev->dev_module; 712246145Shselasky 713246145Shselasky if (DEVICE_PROBE(dev) <= 0) { 714246145Shselasky 715246145Shselasky if (device_allocate_softc(dev) == 0) { 716246145Shselasky 717246145Shselasky if (DEVICE_ATTACH(dev) == 0) { 718246145Shselasky /* success */ 719246145Shselasky dev->dev_attached = 1; 720246145Shselasky return (0); 721246145Shselasky } 722246145Shselasky } 723246145Shselasky } 724246145Shselasky device_detach(dev); 725246145Shselasky 726246145Shselasky goto error; 727246145Shselasky } 728246145Shselasky /* 729246145Shselasky * Else find a module for our device, if any 730246145Shselasky */ 731246145Shselasky 732246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 733246145Shselasky if (devclass_equal(mod->bus_name, bus_name_parent)) { 734246145Shselasky if (devclass_create(mod->devclass_pp)) { 735246145Shselasky continue; 736246145Shselasky } 737246145Shselasky if (devclass_add_device(mod, dev)) { 738246145Shselasky continue; 739246145Shselasky } 740246145Shselasky if (DEVICE_PROBE(dev) <= 0) { 741246145Shselasky 742246145Shselasky if (device_allocate_softc(dev) == 0) { 743246145Shselasky 744246145Shselasky if (DEVICE_ATTACH(dev) == 0) { 745246145Shselasky /* success */ 746246145Shselasky dev->dev_attached = 1; 747246145Shselasky return (0); 748246145Shselasky } 749246145Shselasky } 750246145Shselasky } 751246145Shselasky /* else try next driver */ 752246145Shselasky 753246145Shselasky device_detach(dev); 754246145Shselasky } 755246145Shselasky } 756246145Shselasky 757246145Shselaskyerror: 758246145Shselasky return (ENODEV); 759246145Shselasky} 760246145Shselasky 761246145Shselaskyint 762246145Shselaskydevice_detach(device_t dev) 763246145Shselasky{ 764246145Shselasky const struct module_data *mod = dev->dev_module; 765246145Shselasky int error; 766246145Shselasky 767246145Shselasky if (dev->dev_attached) { 768246145Shselasky 769246145Shselasky error = DEVICE_DETACH(dev); 770246145Shselasky if (error) { 771246145Shselasky return error; 772246145Shselasky } 773246145Shselasky dev->dev_attached = 0; 774246145Shselasky } 775246145Shselasky device_set_softc(dev, NULL); 776246145Shselasky 777246145Shselasky if (dev->dev_fixed_class == 0) 778246145Shselasky devclass_delete_device(mod, dev); 779246145Shselasky 780246145Shselasky return (0); 781246145Shselasky} 782246145Shselasky 783246145Shselaskyvoid 784246145Shselaskydevice_set_softc(device_t dev, void *softc) 785246145Shselasky{ 786246145Shselasky if (dev->dev_softc_alloc) { 787246145Shselasky free(dev->dev_sc, M_DEVBUF); 788246145Shselasky dev->dev_sc = NULL; 789246145Shselasky } 790246145Shselasky dev->dev_sc = softc; 791246145Shselasky dev->dev_softc_alloc = 0; 792246145Shselasky} 793246145Shselasky 794246145Shselaskyvoid * 795246145Shselaskydevice_get_softc(device_t dev) 796246145Shselasky{ 797246145Shselasky if (dev == NULL) 798246145Shselasky return (NULL); 799246145Shselasky 800246145Shselasky return (dev->dev_sc); 801246145Shselasky} 802246145Shselasky 803246145Shselaskyint 804246145Shselaskydevice_is_attached(device_t dev) 805246145Shselasky{ 806246145Shselasky return (dev->dev_attached); 807246145Shselasky} 808246145Shselasky 809246145Shselaskyvoid 810246145Shselaskydevice_set_desc(device_t dev, const char *desc) 811246145Shselasky{ 812246145Shselasky snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc); 813246145Shselasky} 814246145Shselasky 815246145Shselaskyvoid 816246145Shselaskydevice_set_desc_copy(device_t dev, const char *desc) 817246145Shselasky{ 818246145Shselasky device_set_desc(dev, desc); 819246145Shselasky} 820246145Shselasky 821246145Shselaskyvoid * 822246145Shselaskydevclass_get_softc(devclass_t dc, int unit) 823246145Shselasky{ 824246145Shselasky return (device_get_softc(devclass_get_device(dc, unit))); 825246145Shselasky} 826246145Shselasky 827246145Shselaskyint 828246145Shselaskydevclass_get_maxunit(devclass_t dc) 829246145Shselasky{ 830246145Shselasky int max_unit = 0; 831246145Shselasky 832246145Shselasky if (dc) { 833246145Shselasky max_unit = DEVCLASS_MAXUNIT; 834246145Shselasky while (max_unit--) { 835246145Shselasky if (dc->dev_list[max_unit]) { 836246145Shselasky break; 837246145Shselasky } 838246145Shselasky } 839246145Shselasky max_unit++; 840246145Shselasky } 841246145Shselasky return (max_unit); 842246145Shselasky} 843246145Shselasky 844246145Shselaskydevice_t 845246145Shselaskydevclass_get_device(devclass_t dc, int unit) 846246145Shselasky{ 847246145Shselasky return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ? 848246145Shselasky NULL : dc->dev_list[unit]); 849246145Shselasky} 850246145Shselasky 851246145Shselaskydevclass_t 852246145Shselaskydevclass_find(const char *classname) 853246145Shselasky{ 854246145Shselasky const struct module_data *mod; 855246145Shselasky 856246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 857246145Shselasky if (devclass_equal(mod->mod_name, classname)) 858246145Shselasky return (mod->devclass_pp[0]); 859246145Shselasky } 860246145Shselasky return (NULL); 861246145Shselasky} 862246145Shselasky 863246145Shselaskyvoid 864246145Shselaskymodule_register(void *data) 865246145Shselasky{ 866246145Shselasky struct module_data *mdata = data; 867246145Shselasky 868246145Shselasky TAILQ_INSERT_TAIL(&module_head, mdata, entry); 869246145Shselasky} 870246145Shselasky 871246145Shselasky/*------------------------------------------------------------------------* 872246145Shselasky * System startup 873246145Shselasky *------------------------------------------------------------------------*/ 874246145Shselasky 875246145Shselaskystatic void 876246145Shselaskysysinit_run(const void **ppdata) 877246145Shselasky{ 878246145Shselasky const struct sysinit *psys; 879246145Shselasky 880246145Shselasky while ((psys = *ppdata) != NULL) { 881246145Shselasky (psys->func) (psys->data); 882246145Shselasky ppdata++; 883246145Shselasky } 884246145Shselasky} 885246145Shselasky 886246145Shselasky/*------------------------------------------------------------------------* 887246145Shselasky * USB process API 888246145Shselasky *------------------------------------------------------------------------*/ 889246145Shselasky 890246145Shselaskystatic int usb_do_process(struct usb_process *); 891246145Shselaskystatic int usb_proc_level = -1; 892246145Shselaskystatic struct mtx usb_proc_mtx; 893246145Shselasky 894246145Shselaskyvoid 895246145Shselaskyusb_idle(void) 896246145Shselasky{ 897246145Shselasky int old_level = usb_proc_level; 898246145Shselasky int old_giant = Giant.owned; 899246145Shselasky int worked; 900246145Shselasky 901246145Shselasky device_run_interrupts(usb_pci_root); 902246145Shselasky 903246145Shselasky do { 904246145Shselasky worked = 0; 905246145Shselasky Giant.owned = 0; 906246145Shselasky 907246145Shselasky while (++usb_proc_level < USB_PROC_MAX) 908246145Shselasky worked |= usb_do_process(usb_process + usb_proc_level); 909246145Shselasky 910246145Shselasky usb_proc_level = old_level; 911246145Shselasky Giant.owned = old_giant; 912246145Shselasky 913246145Shselasky } while (worked); 914246145Shselasky} 915246145Shselasky 916246145Shselaskyvoid 917246145Shselaskyusb_init(void) 918246145Shselasky{ 919246145Shselasky sysinit_run(sysinit_data); 920246145Shselasky} 921246145Shselasky 922246145Shselaskyvoid 923246145Shselaskyusb_uninit(void) 924246145Shselasky{ 925246145Shselasky sysinit_run(sysuninit_data); 926246145Shselasky} 927246145Shselasky 928246145Shselaskystatic void 929246145Shselaskyusb_process_init_sub(struct usb_process *up) 930246145Shselasky{ 931246145Shselasky TAILQ_INIT(&up->up_qhead); 932246145Shselasky 933246145Shselasky cv_init(&up->up_cv, "-"); 934246145Shselasky cv_init(&up->up_drain, "usbdrain"); 935246145Shselasky 936246145Shselasky up->up_mtx = &usb_proc_mtx; 937246145Shselasky} 938246145Shselasky 939246145Shselaskystatic void 940246145Shselaskyusb_process_init(void *arg) 941246145Shselasky{ 942246145Shselasky uint8_t x; 943246145Shselasky 944246145Shselasky mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE); 945246145Shselasky 946246145Shselasky for (x = 0; x != USB_PROC_MAX; x++) 947246145Shselasky usb_process_init_sub(&usb_process[x]); 948246145Shselasky 949246145Shselasky} 950246145ShselaskySYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL); 951246145Shselasky 952246145Shselaskystatic int 953246145Shselaskyusb_do_process(struct usb_process *up) 954246145Shselasky{ 955246145Shselasky struct usb_proc_msg *pm; 956246145Shselasky int worked = 0; 957246145Shselasky 958246145Shselasky mtx_lock(&usb_proc_mtx); 959246145Shselasky 960246145Shselaskyrepeat: 961246145Shselasky pm = TAILQ_FIRST(&up->up_qhead); 962246145Shselasky 963246145Shselasky if (pm != NULL) { 964246145Shselasky 965246145Shselasky worked = 1; 966246145Shselasky 967246145Shselasky (pm->pm_callback) (pm); 968246145Shselasky 969246145Shselasky if (pm == TAILQ_FIRST(&up->up_qhead)) { 970246145Shselasky /* nothing changed */ 971246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); 972246145Shselasky pm->pm_qentry.tqe_prev = NULL; 973246145Shselasky } 974246145Shselasky goto repeat; 975246145Shselasky } 976246145Shselasky mtx_unlock(&usb_proc_mtx); 977246145Shselasky 978246145Shselasky return (worked); 979246145Shselasky} 980246145Shselasky 981246145Shselaskyvoid * 982246145Shselaskyusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1) 983246145Shselasky{ 984246145Shselasky struct usb_proc_msg *pm0 = _pm0; 985246145Shselasky struct usb_proc_msg *pm1 = _pm1; 986246145Shselasky struct usb_proc_msg *pm2; 987246145Shselasky usb_size_t d; 988246145Shselasky uint8_t t; 989246145Shselasky 990246145Shselasky t = 0; 991246145Shselasky 992246145Shselasky if (pm0->pm_qentry.tqe_prev) { 993246145Shselasky t |= 1; 994246145Shselasky } 995246145Shselasky if (pm1->pm_qentry.tqe_prev) { 996246145Shselasky t |= 2; 997246145Shselasky } 998246145Shselasky if (t == 0) { 999246145Shselasky /* 1000246145Shselasky * No entries are queued. Queue "pm0" and use the existing 1001246145Shselasky * message number. 1002246145Shselasky */ 1003246145Shselasky pm2 = pm0; 1004246145Shselasky } else if (t == 1) { 1005246145Shselasky /* Check if we need to increment the message number. */ 1006246145Shselasky if (pm0->pm_num == up->up_msg_num) { 1007246145Shselasky up->up_msg_num++; 1008246145Shselasky } 1009246145Shselasky pm2 = pm1; 1010246145Shselasky } else if (t == 2) { 1011246145Shselasky /* Check if we need to increment the message number. */ 1012246145Shselasky if (pm1->pm_num == up->up_msg_num) { 1013246145Shselasky up->up_msg_num++; 1014246145Shselasky } 1015246145Shselasky pm2 = pm0; 1016246145Shselasky } else if (t == 3) { 1017246145Shselasky /* 1018246145Shselasky * Both entries are queued. Re-queue the entry closest to 1019246145Shselasky * the end. 1020246145Shselasky */ 1021246145Shselasky d = (pm1->pm_num - pm0->pm_num); 1022246145Shselasky 1023246145Shselasky /* Check sign after subtraction */ 1024246145Shselasky if (d & 0x80000000) { 1025246145Shselasky pm2 = pm0; 1026246145Shselasky } else { 1027246145Shselasky pm2 = pm1; 1028246145Shselasky } 1029246145Shselasky 1030246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry); 1031246145Shselasky } else { 1032246145Shselasky pm2 = NULL; /* panic - should not happen */ 1033246145Shselasky } 1034246145Shselasky 1035246145Shselasky /* Put message last on queue */ 1036246145Shselasky 1037246145Shselasky pm2->pm_num = up->up_msg_num; 1038246145Shselasky TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry); 1039246145Shselasky 1040246145Shselasky return (pm2); 1041246145Shselasky} 1042246145Shselasky 1043246145Shselasky/*------------------------------------------------------------------------* 1044246145Shselasky * usb_proc_is_gone 1045246145Shselasky * 1046246145Shselasky * Return values: 1047246145Shselasky * 0: USB process is running 1048246145Shselasky * Else: USB process is tearing down 1049246145Shselasky *------------------------------------------------------------------------*/ 1050246145Shselaskyuint8_t 1051246145Shselaskyusb_proc_is_gone(struct usb_process *up) 1052246145Shselasky{ 1053246145Shselasky return (0); 1054246145Shselasky} 1055246145Shselasky 1056246145Shselasky/*------------------------------------------------------------------------* 1057246145Shselasky * usb_proc_mwait 1058246145Shselasky * 1059246145Shselasky * This function will return when the USB process message pointed to 1060246145Shselasky * by "pm" is no longer on a queue. This function must be called 1061246145Shselasky * having "usb_proc_mtx" locked. 1062246145Shselasky *------------------------------------------------------------------------*/ 1063246145Shselaskyvoid 1064246145Shselaskyusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1) 1065246145Shselasky{ 1066246145Shselasky struct usb_proc_msg *pm0 = _pm0; 1067246145Shselasky struct usb_proc_msg *pm1 = _pm1; 1068246145Shselasky 1069246145Shselasky /* Just remove the messages from the queue. */ 1070246145Shselasky if (pm0->pm_qentry.tqe_prev) { 1071246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry); 1072246145Shselasky pm0->pm_qentry.tqe_prev = NULL; 1073246145Shselasky } 1074246145Shselasky if (pm1->pm_qentry.tqe_prev) { 1075246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry); 1076246145Shselasky pm1->pm_qentry.tqe_prev = NULL; 1077246145Shselasky } 1078246145Shselasky} 1079246145Shselasky 1080246145Shselasky/*------------------------------------------------------------------------* 1081246145Shselasky * SYSTEM attach 1082246145Shselasky *------------------------------------------------------------------------*/ 1083246145Shselasky 1084246145Shselaskystatic device_method_t pci_methods[] = { 1085246145Shselasky DEVMETHOD_END 1086246145Shselasky}; 1087246145Shselasky 1088246145Shselaskystatic driver_t pci_driver = { 1089246145Shselasky .name = "pci", 1090246145Shselasky .methods = pci_methods, 1091246145Shselasky}; 1092246145Shselasky 1093246145Shselaskystatic devclass_t pci_devclass; 1094246145Shselasky 1095246145ShselaskyDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0); 1096246145Shselasky 1097246145Shselaskystatic const char *usb_pci_devices[] = { 1098246145Shselasky#ifdef USB_PROBE_LIST 1099246145Shselasky USB_PROBE_LIST 1100246145Shselasky#endif 1101246145Shselasky}; 1102246145Shselasky 1103246145Shselasky#define USB_PCI_USB_MAX (sizeof(usb_pci_devices) / sizeof(void *)) 1104246145Shselasky 1105246145Shselaskystatic device_t usb_pci_dev[USB_PCI_USB_MAX]; 1106246145Shselasky 1107246145Shselaskystatic void 1108246145Shselaskyusb_pci_mod_load(void *arg) 1109246145Shselasky{ 1110246145Shselasky uint32_t x; 1111246145Shselasky 1112246145Shselasky usb_pci_root = device_add_child(NULL, "pci", -1); 1113246145Shselasky if (usb_pci_root == NULL) 1114246145Shselasky return; 1115246145Shselasky 1116246145Shselasky for (x = 0; x != USB_PCI_USB_MAX; x++) { 1117246145Shselasky usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1); 1118246145Shselasky if (usb_pci_dev[x] == NULL) 1119246145Shselasky continue; 1120246145Shselasky if (device_probe_and_attach(usb_pci_dev[x])) { 1121246145Shselasky device_printf(usb_pci_dev[x], 1122246145Shselasky "WARNING: Probe and attach failed!\n"); 1123246145Shselasky } 1124246145Shselasky } 1125246145Shselasky} 1126246145ShselaskySYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0); 1127246145Shselasky 1128246145Shselaskystatic void 1129246145Shselaskyusb_pci_mod_unload(void *arg) 1130246145Shselasky{ 1131246145Shselasky uint32_t x; 1132246145Shselasky 1133246145Shselasky for (x = 0; x != USB_PCI_USB_MAX; x++) { 1134246145Shselasky if (usb_pci_dev[x]) { 1135246145Shselasky device_detach(usb_pci_dev[x]); 1136246145Shselasky device_delete_child(usb_pci_root, usb_pci_dev[x]); 1137246145Shselasky } 1138246145Shselasky } 1139246145Shselasky if (usb_pci_root) 1140246145Shselasky device_delete_child(NULL, usb_pci_root); 1141246145Shselasky} 1142246145ShselaskySYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0); 1143246145Shselasky 1144246145Shselasky/*------------------------------------------------------------------------* 1145246145Shselasky * MALLOC API 1146246145Shselasky *------------------------------------------------------------------------*/ 1147246145Shselasky 1148246145Shselasky#define USB_POOL_ALIGN 8 1149246145Shselasky 1150246145Shselaskystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN); 1151246145Shselaskystatic uint32_t usb_pool_rem = USB_POOL_SIZE; 1152246145Shselaskystatic uint32_t usb_pool_entries; 1153246145Shselasky 1154246145Shselaskystruct malloc_hdr { 1155246145Shselasky TAILQ_ENTRY(malloc_hdr) entry; 1156246145Shselasky uint32_t size; 1157246145Shselasky} __aligned(USB_POOL_ALIGN); 1158246145Shselasky 1159246145Shselaskystatic TAILQ_HEAD(, malloc_hdr) malloc_head = 1160246145Shselasky TAILQ_HEAD_INITIALIZER(malloc_head); 1161246145Shselasky 1162246145Shselaskyvoid * 1163246145Shselaskyusb_malloc(unsigned long size) 1164246145Shselasky{ 1165246145Shselasky struct malloc_hdr *hdr; 1166246145Shselasky 1167246145Shselasky size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1); 1168246145Shselasky size += sizeof(struct malloc_hdr); 1169246145Shselasky 1170246145Shselasky TAILQ_FOREACH(hdr, &malloc_head, entry) { 1171246145Shselasky if (hdr->size == size) 1172246145Shselasky break; 1173246145Shselasky } 1174246145Shselasky 1175246145Shselasky if (hdr) { 1176246145Shselasky printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1177246145Shselasky (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1178246145Shselasky 1179246145Shselasky TAILQ_REMOVE(&malloc_head, hdr, entry); 1180246145Shselasky memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1181246145Shselasky return (hdr + 1); 1182246145Shselasky } 1183246145Shselasky if (usb_pool_rem >= size) { 1184246145Shselasky hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem); 1185246145Shselasky hdr->size = size; 1186246145Shselasky 1187246145Shselasky usb_pool_rem -= size; 1188246145Shselasky usb_pool_entries++; 1189246145Shselasky 1190246145Shselasky printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1191246145Shselasky (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1192246145Shselasky 1193246145Shselasky memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1194246145Shselasky return (hdr + 1); 1195246145Shselasky } 1196246145Shselasky return (NULL); 1197246145Shselasky} 1198246145Shselasky 1199246145Shselaskyvoid 1200246145Shselaskyusb_free(void *arg) 1201246145Shselasky{ 1202246145Shselasky struct malloc_hdr *hdr; 1203246145Shselasky 1204246145Shselasky if (arg == NULL) 1205246145Shselasky return; 1206246145Shselasky 1207246145Shselasky hdr = arg; 1208246145Shselasky hdr--; 1209246145Shselasky 1210246145Shselasky TAILQ_INSERT_TAIL(&malloc_head, hdr, entry); 1211246145Shselasky} 1212246145Shselasky 1213246145Shselaskychar * 1214246145Shselaskyusb_strdup(const char *str) 1215246145Shselasky{ 1216246145Shselasky char *tmp; 1217246145Shselasky int len; 1218246145Shselasky 1219246145Shselasky len = 1 + strlen(str); 1220246145Shselasky 1221246145Shselasky tmp = usb_malloc(len); 1222246145Shselasky if (tmp == NULL) 1223246145Shselasky return (NULL); 1224246145Shselasky 1225246145Shselasky memcpy(tmp, str, len); 1226246145Shselasky return (tmp); 1227246145Shselasky} 1228