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 383269921Shselaskydevice_set_interrupt(device_t dev, driver_filter_t *filter, 384269921Shselasky driver_intr_t *fn, void *arg) 385246145Shselasky{ 386269921Shselasky dev->dev_irq_filter = filter; 387246145Shselasky dev->dev_irq_fn = fn; 388246145Shselasky dev->dev_irq_arg = arg; 389246145Shselasky} 390246145Shselasky 391246145Shselaskyvoid 392246145Shselaskydevice_run_interrupts(device_t parent) 393246145Shselasky{ 394246145Shselasky device_t child; 395246145Shselasky 396246145Shselasky if (parent == NULL) 397246145Shselasky return; 398246145Shselasky 399246145Shselasky TAILQ_FOREACH(child, &parent->dev_children, dev_link) { 400269921Shselasky int status; 401269921Shselasky if (child->dev_irq_filter != NULL) 402269921Shselasky status = child->dev_irq_filter(child->dev_irq_arg); 403269921Shselasky else 404269921Shselasky status = FILTER_SCHEDULE_THREAD; 405269921Shselasky 406269921Shselasky if (status == FILTER_SCHEDULE_THREAD) { 407269921Shselasky if (child->dev_irq_fn != NULL) 408269921Shselasky (child->dev_irq_fn) (child->dev_irq_arg); 409269921Shselasky } 410246145Shselasky } 411246145Shselasky} 412246145Shselasky 413246145Shselaskyvoid 414246145Shselaskydevice_set_ivars(device_t dev, void *ivars) 415246145Shselasky{ 416246145Shselasky dev->dev_aux = ivars; 417246145Shselasky} 418246145Shselasky 419246145Shselaskyvoid * 420246145Shselaskydevice_get_ivars(device_t dev) 421246145Shselasky{ 422246145Shselasky return (dev ? dev->dev_aux : NULL); 423246145Shselasky} 424246145Shselasky 425246145Shselaskyint 426246145Shselaskydevice_get_unit(device_t dev) 427246145Shselasky{ 428246145Shselasky return (dev ? dev->dev_unit : 0); 429246145Shselasky} 430246145Shselasky 431246145Shselaskyint 432246145Shselaskybus_generic_detach(device_t dev) 433246145Shselasky{ 434246145Shselasky device_t child; 435246145Shselasky int error; 436246145Shselasky 437246145Shselasky if (!dev->dev_attached) 438246145Shselasky return (EBUSY); 439246145Shselasky 440246145Shselasky TAILQ_FOREACH(child, &dev->dev_children, dev_link) { 441246145Shselasky if ((error = device_detach(child)) != 0) 442246145Shselasky return (error); 443246145Shselasky } 444246145Shselasky return (0); 445246145Shselasky} 446246145Shselasky 447246145Shselaskyconst char * 448246145Shselaskydevice_get_nameunit(device_t dev) 449246145Shselasky{ 450246145Shselasky if (dev && dev->dev_nameunit[0]) 451246145Shselasky return (dev->dev_nameunit); 452246145Shselasky 453246145Shselasky return (unknown_string); 454246145Shselasky} 455246145Shselasky 456246145Shselaskystatic uint8_t 457246145Shselaskydevclass_create(devclass_t *dc_pp) 458246145Shselasky{ 459246145Shselasky if (dc_pp == NULL) { 460246145Shselasky return (1); 461246145Shselasky } 462246145Shselasky if (dc_pp[0] == NULL) { 463246145Shselasky dc_pp[0] = malloc(sizeof(**(dc_pp)), 464246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 465246145Shselasky 466246145Shselasky if (dc_pp[0] == NULL) { 467246145Shselasky return (1); 468246145Shselasky } 469246145Shselasky } 470246145Shselasky return (0); 471246145Shselasky} 472246145Shselasky 473246145Shselaskystatic const struct module_data * 474246145Shselaskydevclass_find_create(const char *classname) 475246145Shselasky{ 476246145Shselasky const struct module_data *mod; 477246145Shselasky 478246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 479246145Shselasky if (devclass_equal(mod->mod_name, classname)) { 480246145Shselasky if (devclass_create(mod->devclass_pp)) { 481246145Shselasky continue; 482246145Shselasky } 483246145Shselasky return (mod); 484246145Shselasky } 485246145Shselasky } 486246145Shselasky return (NULL); 487246145Shselasky} 488246145Shselasky 489246145Shselaskystatic uint8_t 490246145Shselaskydevclass_add_device(const struct module_data *mod, device_t dev) 491246145Shselasky{ 492246145Shselasky device_t *pp_dev; 493246145Shselasky device_t *end; 494246145Shselasky uint8_t unit; 495246145Shselasky 496246145Shselasky pp_dev = mod->devclass_pp[0]->dev_list; 497246145Shselasky end = pp_dev + DEVCLASS_MAXUNIT; 498246145Shselasky unit = 0; 499246145Shselasky 500246145Shselasky while (pp_dev != end) { 501246145Shselasky if (*pp_dev == NULL) { 502246145Shselasky *pp_dev = dev; 503246145Shselasky dev->dev_unit = unit; 504246145Shselasky dev->dev_module = mod; 505246145Shselasky snprintf(dev->dev_nameunit, 506246145Shselasky sizeof(dev->dev_nameunit), 507246145Shselasky "%s%d", device_get_name(dev), unit); 508246145Shselasky return (0); 509246145Shselasky } 510246145Shselasky pp_dev++; 511246145Shselasky unit++; 512246145Shselasky } 513246145Shselasky DPRINTF("Could not add device to devclass.\n"); 514246145Shselasky return (1); 515246145Shselasky} 516246145Shselasky 517246145Shselaskystatic void 518246145Shselaskydevclass_delete_device(const struct module_data *mod, device_t dev) 519246145Shselasky{ 520246145Shselasky if (mod == NULL) { 521246145Shselasky return; 522246145Shselasky } 523246145Shselasky mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL; 524246145Shselasky dev->dev_module = NULL; 525246145Shselasky} 526246145Shselasky 527246145Shselaskystatic device_t 528246145Shselaskymake_device(device_t parent, const char *name) 529246145Shselasky{ 530246145Shselasky device_t dev = NULL; 531246145Shselasky const struct module_data *mod = NULL; 532246145Shselasky 533246145Shselasky if (name) { 534246145Shselasky 535246145Shselasky mod = devclass_find_create(name); 536246145Shselasky 537246145Shselasky if (!mod) { 538246145Shselasky 539246145Shselasky DPRINTF("%s:%d:%s: can't find device " 540246145Shselasky "class %s\n", __FILE__, __LINE__, 541246145Shselasky __FUNCTION__, name); 542246145Shselasky 543246145Shselasky goto done; 544246145Shselasky } 545246145Shselasky } 546246145Shselasky dev = malloc(sizeof(*dev), 547246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 548246145Shselasky 549246145Shselasky if (dev == NULL) 550246145Shselasky goto done; 551246145Shselasky 552246145Shselasky dev->dev_parent = parent; 553246145Shselasky TAILQ_INIT(&dev->dev_children); 554246145Shselasky 555246145Shselasky if (name) { 556246145Shselasky dev->dev_fixed_class = 1; 557246145Shselasky if (devclass_add_device(mod, dev)) { 558246145Shselasky goto error; 559246145Shselasky } 560246145Shselasky } 561246145Shselaskydone: 562246145Shselasky return (dev); 563246145Shselasky 564246145Shselaskyerror: 565246145Shselasky if (dev) { 566246145Shselasky free(dev, M_DEVBUF); 567246145Shselasky } 568246145Shselasky return (NULL); 569246145Shselasky} 570246145Shselasky 571246145Shselaskydevice_t 572246145Shselaskydevice_add_child(device_t dev, const char *name, int unit) 573246145Shselasky{ 574246145Shselasky device_t child; 575246145Shselasky 576246145Shselasky if (unit != -1) { 577246145Shselasky device_printf(dev, "Unit is not -1\n"); 578246145Shselasky } 579246145Shselasky child = make_device(dev, name); 580246145Shselasky if (child == NULL) { 581246145Shselasky device_printf(dev, "Could not add child '%s'\n", name); 582246145Shselasky goto done; 583246145Shselasky } 584246145Shselasky if (dev == NULL) { 585246145Shselasky /* no parent */ 586246145Shselasky goto done; 587246145Shselasky } 588246145Shselasky TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link); 589246145Shselaskydone: 590246145Shselasky return (child); 591246145Shselasky} 592246145Shselasky 593246145Shselaskyint 594246145Shselaskydevice_delete_child(device_t dev, device_t child) 595246145Shselasky{ 596246145Shselasky int error = 0; 597246145Shselasky device_t grandchild; 598246145Shselasky 599246145Shselasky /* remove children first */ 600246145Shselasky 601246145Shselasky while ((grandchild = TAILQ_FIRST(&child->dev_children))) { 602246145Shselasky error = device_delete_child(child, grandchild); 603246145Shselasky if (error) { 604246145Shselasky device_printf(dev, "Error deleting child!\n"); 605246145Shselasky goto done; 606246145Shselasky } 607246145Shselasky } 608246145Shselasky 609246145Shselasky error = device_detach(child); 610246145Shselasky 611246145Shselasky if (error) 612246145Shselasky goto done; 613246145Shselasky 614246145Shselasky devclass_delete_device(child->dev_module, child); 615246145Shselasky 616246145Shselasky if (dev != NULL) { 617246145Shselasky /* remove child from parent */ 618246145Shselasky TAILQ_REMOVE(&dev->dev_children, child, dev_link); 619246145Shselasky } 620246145Shselasky free(child, M_DEVBUF); 621246145Shselasky 622246145Shselaskydone: 623246145Shselasky return (error); 624246145Shselasky} 625246145Shselasky 626246145Shselaskyint 627246145Shselaskydevice_delete_children(device_t dev) 628246145Shselasky{ 629246145Shselasky device_t child; 630246145Shselasky int error = 0; 631246145Shselasky 632246145Shselasky while ((child = TAILQ_FIRST(&dev->dev_children))) { 633246145Shselasky error = device_delete_child(dev, child); 634246145Shselasky if (error) { 635246145Shselasky device_printf(dev, "Error deleting child!\n"); 636246145Shselasky break; 637246145Shselasky } 638246145Shselasky } 639246145Shselasky return (error); 640246145Shselasky} 641246145Shselasky 642246145Shselaskyvoid 643246145Shselaskydevice_quiet(device_t dev) 644246145Shselasky{ 645246145Shselasky dev->dev_quiet = 1; 646246145Shselasky} 647246145Shselasky 648246145Shselaskyconst char * 649246145Shselaskydevice_get_desc(device_t dev) 650246145Shselasky{ 651246145Shselasky if (dev) 652246145Shselasky return &(dev->dev_desc[0]); 653246145Shselasky return (unknown_string); 654246145Shselasky} 655246145Shselasky 656246145Shselaskystatic int 657246145Shselaskydefault_method(void) 658246145Shselasky{ 659246145Shselasky /* do nothing */ 660246145Shselasky DPRINTF("Default method called\n"); 661246145Shselasky return (0); 662246145Shselasky} 663246145Shselasky 664246145Shselaskyvoid * 665246145Shselaskydevice_get_method(device_t dev, const char *what) 666246145Shselasky{ 667246145Shselasky const struct device_method *mtod; 668246145Shselasky 669246145Shselasky mtod = dev->dev_module->driver->methods; 670246145Shselasky while (mtod->func != NULL) { 671246145Shselasky if (devclass_equal(mtod->desc, what)) { 672246145Shselasky return (mtod->func); 673246145Shselasky } 674246145Shselasky mtod++; 675246145Shselasky } 676246145Shselasky return ((void *)&default_method); 677246145Shselasky} 678246145Shselasky 679246145Shselaskyconst char * 680246145Shselaskydevice_get_name(device_t dev) 681246145Shselasky{ 682246145Shselasky if (dev == NULL) 683246145Shselasky return (unknown_string); 684246145Shselasky 685246145Shselasky return (dev->dev_module->driver->name); 686246145Shselasky} 687246145Shselasky 688246145Shselaskystatic int 689246145Shselaskydevice_allocate_softc(device_t dev) 690246145Shselasky{ 691246145Shselasky const struct module_data *mod; 692246145Shselasky 693246145Shselasky mod = dev->dev_module; 694246145Shselasky 695246145Shselasky if ((dev->dev_softc_alloc == 0) && 696246145Shselasky (mod->driver->size != 0)) { 697246145Shselasky dev->dev_sc = malloc(mod->driver->size, 698246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 699246145Shselasky 700246145Shselasky if (dev->dev_sc == NULL) 701246145Shselasky return (ENOMEM); 702246145Shselasky 703246145Shselasky dev->dev_softc_alloc = 1; 704246145Shselasky } 705246145Shselasky return (0); 706246145Shselasky} 707246145Shselasky 708246145Shselaskyint 709246145Shselaskydevice_probe_and_attach(device_t dev) 710246145Shselasky{ 711246145Shselasky const struct module_data *mod; 712246145Shselasky const char *bus_name_parent; 713246145Shselasky 714246145Shselasky bus_name_parent = device_get_name(device_get_parent(dev)); 715246145Shselasky 716246145Shselasky if (dev->dev_attached) 717246145Shselasky return (0); /* fail-safe */ 718246145Shselasky 719246145Shselasky if (dev->dev_fixed_class) { 720246145Shselasky 721246145Shselasky mod = dev->dev_module; 722246145Shselasky 723246145Shselasky if (DEVICE_PROBE(dev) <= 0) { 724246145Shselasky 725246145Shselasky if (device_allocate_softc(dev) == 0) { 726246145Shselasky 727246145Shselasky if (DEVICE_ATTACH(dev) == 0) { 728246145Shselasky /* success */ 729246145Shselasky dev->dev_attached = 1; 730246145Shselasky return (0); 731246145Shselasky } 732246145Shselasky } 733246145Shselasky } 734246145Shselasky device_detach(dev); 735246145Shselasky 736246145Shselasky goto error; 737246145Shselasky } 738246145Shselasky /* 739246145Shselasky * Else find a module for our device, if any 740246145Shselasky */ 741246145Shselasky 742246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 743246145Shselasky if (devclass_equal(mod->bus_name, bus_name_parent)) { 744246145Shselasky if (devclass_create(mod->devclass_pp)) { 745246145Shselasky continue; 746246145Shselasky } 747246145Shselasky if (devclass_add_device(mod, dev)) { 748246145Shselasky continue; 749246145Shselasky } 750246145Shselasky if (DEVICE_PROBE(dev) <= 0) { 751246145Shselasky 752246145Shselasky if (device_allocate_softc(dev) == 0) { 753246145Shselasky 754246145Shselasky if (DEVICE_ATTACH(dev) == 0) { 755246145Shselasky /* success */ 756246145Shselasky dev->dev_attached = 1; 757246145Shselasky return (0); 758246145Shselasky } 759246145Shselasky } 760246145Shselasky } 761246145Shselasky /* else try next driver */ 762246145Shselasky 763246145Shselasky device_detach(dev); 764246145Shselasky } 765246145Shselasky } 766246145Shselasky 767246145Shselaskyerror: 768246145Shselasky return (ENODEV); 769246145Shselasky} 770246145Shselasky 771246145Shselaskyint 772246145Shselaskydevice_detach(device_t dev) 773246145Shselasky{ 774246145Shselasky const struct module_data *mod = dev->dev_module; 775246145Shselasky int error; 776246145Shselasky 777246145Shselasky if (dev->dev_attached) { 778246145Shselasky 779246145Shselasky error = DEVICE_DETACH(dev); 780246145Shselasky if (error) { 781246145Shselasky return error; 782246145Shselasky } 783246145Shselasky dev->dev_attached = 0; 784246145Shselasky } 785246145Shselasky device_set_softc(dev, NULL); 786246145Shselasky 787246145Shselasky if (dev->dev_fixed_class == 0) 788246145Shselasky devclass_delete_device(mod, dev); 789246145Shselasky 790246145Shselasky return (0); 791246145Shselasky} 792246145Shselasky 793246145Shselaskyvoid 794246145Shselaskydevice_set_softc(device_t dev, void *softc) 795246145Shselasky{ 796246145Shselasky if (dev->dev_softc_alloc) { 797246145Shselasky free(dev->dev_sc, M_DEVBUF); 798246145Shselasky dev->dev_sc = NULL; 799246145Shselasky } 800246145Shselasky dev->dev_sc = softc; 801246145Shselasky dev->dev_softc_alloc = 0; 802246145Shselasky} 803246145Shselasky 804246145Shselaskyvoid * 805246145Shselaskydevice_get_softc(device_t dev) 806246145Shselasky{ 807246145Shselasky if (dev == NULL) 808246145Shselasky return (NULL); 809246145Shselasky 810246145Shselasky return (dev->dev_sc); 811246145Shselasky} 812246145Shselasky 813246145Shselaskyint 814246145Shselaskydevice_is_attached(device_t dev) 815246145Shselasky{ 816246145Shselasky return (dev->dev_attached); 817246145Shselasky} 818246145Shselasky 819246145Shselaskyvoid 820246145Shselaskydevice_set_desc(device_t dev, const char *desc) 821246145Shselasky{ 822246145Shselasky snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc); 823246145Shselasky} 824246145Shselasky 825246145Shselaskyvoid 826246145Shselaskydevice_set_desc_copy(device_t dev, const char *desc) 827246145Shselasky{ 828246145Shselasky device_set_desc(dev, desc); 829246145Shselasky} 830246145Shselasky 831246145Shselaskyvoid * 832246145Shselaskydevclass_get_softc(devclass_t dc, int unit) 833246145Shselasky{ 834246145Shselasky return (device_get_softc(devclass_get_device(dc, unit))); 835246145Shselasky} 836246145Shselasky 837246145Shselaskyint 838246145Shselaskydevclass_get_maxunit(devclass_t dc) 839246145Shselasky{ 840246145Shselasky int max_unit = 0; 841246145Shselasky 842246145Shselasky if (dc) { 843246145Shselasky max_unit = DEVCLASS_MAXUNIT; 844246145Shselasky while (max_unit--) { 845246145Shselasky if (dc->dev_list[max_unit]) { 846246145Shselasky break; 847246145Shselasky } 848246145Shselasky } 849246145Shselasky max_unit++; 850246145Shselasky } 851246145Shselasky return (max_unit); 852246145Shselasky} 853246145Shselasky 854246145Shselaskydevice_t 855246145Shselaskydevclass_get_device(devclass_t dc, int unit) 856246145Shselasky{ 857246145Shselasky return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ? 858246145Shselasky NULL : dc->dev_list[unit]); 859246145Shselasky} 860246145Shselasky 861246145Shselaskydevclass_t 862246145Shselaskydevclass_find(const char *classname) 863246145Shselasky{ 864246145Shselasky const struct module_data *mod; 865246145Shselasky 866246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 867246145Shselasky if (devclass_equal(mod->mod_name, classname)) 868246145Shselasky return (mod->devclass_pp[0]); 869246145Shselasky } 870246145Shselasky return (NULL); 871246145Shselasky} 872246145Shselasky 873246145Shselaskyvoid 874246145Shselaskymodule_register(void *data) 875246145Shselasky{ 876246145Shselasky struct module_data *mdata = data; 877246145Shselasky 878246145Shselasky TAILQ_INSERT_TAIL(&module_head, mdata, entry); 879246145Shselasky} 880246145Shselasky 881246145Shselasky/*------------------------------------------------------------------------* 882246145Shselasky * System startup 883246145Shselasky *------------------------------------------------------------------------*/ 884246145Shselasky 885246145Shselaskystatic void 886246145Shselaskysysinit_run(const void **ppdata) 887246145Shselasky{ 888246145Shselasky const struct sysinit *psys; 889246145Shselasky 890246145Shselasky while ((psys = *ppdata) != NULL) { 891246145Shselasky (psys->func) (psys->data); 892246145Shselasky ppdata++; 893246145Shselasky } 894246145Shselasky} 895246145Shselasky 896246145Shselasky/*------------------------------------------------------------------------* 897246145Shselasky * USB process API 898246145Shselasky *------------------------------------------------------------------------*/ 899246145Shselasky 900246145Shselaskystatic int usb_do_process(struct usb_process *); 901246145Shselaskystatic int usb_proc_level = -1; 902246145Shselaskystatic struct mtx usb_proc_mtx; 903246145Shselasky 904246145Shselaskyvoid 905246145Shselaskyusb_idle(void) 906246145Shselasky{ 907246145Shselasky int old_level = usb_proc_level; 908246145Shselasky int old_giant = Giant.owned; 909246145Shselasky int worked; 910246145Shselasky 911246145Shselasky device_run_interrupts(usb_pci_root); 912246145Shselasky 913246145Shselasky do { 914246145Shselasky worked = 0; 915246145Shselasky Giant.owned = 0; 916246145Shselasky 917246145Shselasky while (++usb_proc_level < USB_PROC_MAX) 918246145Shselasky worked |= usb_do_process(usb_process + usb_proc_level); 919246145Shselasky 920246145Shselasky usb_proc_level = old_level; 921246145Shselasky Giant.owned = old_giant; 922246145Shselasky 923246145Shselasky } while (worked); 924246145Shselasky} 925246145Shselasky 926246145Shselaskyvoid 927246145Shselaskyusb_init(void) 928246145Shselasky{ 929246145Shselasky sysinit_run(sysinit_data); 930246145Shselasky} 931246145Shselasky 932246145Shselaskyvoid 933246145Shselaskyusb_uninit(void) 934246145Shselasky{ 935246145Shselasky sysinit_run(sysuninit_data); 936246145Shselasky} 937246145Shselasky 938246145Shselaskystatic void 939246145Shselaskyusb_process_init_sub(struct usb_process *up) 940246145Shselasky{ 941246145Shselasky TAILQ_INIT(&up->up_qhead); 942246145Shselasky 943246145Shselasky cv_init(&up->up_cv, "-"); 944246145Shselasky cv_init(&up->up_drain, "usbdrain"); 945246145Shselasky 946246145Shselasky up->up_mtx = &usb_proc_mtx; 947246145Shselasky} 948246145Shselasky 949246145Shselaskystatic void 950246145Shselaskyusb_process_init(void *arg) 951246145Shselasky{ 952246145Shselasky uint8_t x; 953246145Shselasky 954246145Shselasky mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE); 955246145Shselasky 956246145Shselasky for (x = 0; x != USB_PROC_MAX; x++) 957246145Shselasky usb_process_init_sub(&usb_process[x]); 958246145Shselasky 959246145Shselasky} 960246145ShselaskySYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL); 961246145Shselasky 962246145Shselaskystatic int 963246145Shselaskyusb_do_process(struct usb_process *up) 964246145Shselasky{ 965246145Shselasky struct usb_proc_msg *pm; 966246145Shselasky int worked = 0; 967246145Shselasky 968246145Shselasky mtx_lock(&usb_proc_mtx); 969246145Shselasky 970246145Shselaskyrepeat: 971246145Shselasky pm = TAILQ_FIRST(&up->up_qhead); 972246145Shselasky 973246145Shselasky if (pm != NULL) { 974246145Shselasky 975246145Shselasky worked = 1; 976246145Shselasky 977246145Shselasky (pm->pm_callback) (pm); 978246145Shselasky 979246145Shselasky if (pm == TAILQ_FIRST(&up->up_qhead)) { 980246145Shselasky /* nothing changed */ 981246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); 982246145Shselasky pm->pm_qentry.tqe_prev = NULL; 983246145Shselasky } 984246145Shselasky goto repeat; 985246145Shselasky } 986246145Shselasky mtx_unlock(&usb_proc_mtx); 987246145Shselasky 988246145Shselasky return (worked); 989246145Shselasky} 990246145Shselasky 991246145Shselaskyvoid * 992246145Shselaskyusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1) 993246145Shselasky{ 994246145Shselasky struct usb_proc_msg *pm0 = _pm0; 995246145Shselasky struct usb_proc_msg *pm1 = _pm1; 996246145Shselasky struct usb_proc_msg *pm2; 997246145Shselasky usb_size_t d; 998246145Shselasky uint8_t t; 999246145Shselasky 1000246145Shselasky t = 0; 1001246145Shselasky 1002246145Shselasky if (pm0->pm_qentry.tqe_prev) { 1003246145Shselasky t |= 1; 1004246145Shselasky } 1005246145Shselasky if (pm1->pm_qentry.tqe_prev) { 1006246145Shselasky t |= 2; 1007246145Shselasky } 1008246145Shselasky if (t == 0) { 1009246145Shselasky /* 1010246145Shselasky * No entries are queued. Queue "pm0" and use the existing 1011246145Shselasky * message number. 1012246145Shselasky */ 1013246145Shselasky pm2 = pm0; 1014246145Shselasky } else if (t == 1) { 1015246145Shselasky /* Check if we need to increment the message number. */ 1016246145Shselasky if (pm0->pm_num == up->up_msg_num) { 1017246145Shselasky up->up_msg_num++; 1018246145Shselasky } 1019246145Shselasky pm2 = pm1; 1020246145Shselasky } else if (t == 2) { 1021246145Shselasky /* Check if we need to increment the message number. */ 1022246145Shselasky if (pm1->pm_num == up->up_msg_num) { 1023246145Shselasky up->up_msg_num++; 1024246145Shselasky } 1025246145Shselasky pm2 = pm0; 1026246145Shselasky } else if (t == 3) { 1027246145Shselasky /* 1028246145Shselasky * Both entries are queued. Re-queue the entry closest to 1029246145Shselasky * the end. 1030246145Shselasky */ 1031246145Shselasky d = (pm1->pm_num - pm0->pm_num); 1032246145Shselasky 1033246145Shselasky /* Check sign after subtraction */ 1034246145Shselasky if (d & 0x80000000) { 1035246145Shselasky pm2 = pm0; 1036246145Shselasky } else { 1037246145Shselasky pm2 = pm1; 1038246145Shselasky } 1039246145Shselasky 1040246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry); 1041246145Shselasky } else { 1042246145Shselasky pm2 = NULL; /* panic - should not happen */ 1043246145Shselasky } 1044246145Shselasky 1045246145Shselasky /* Put message last on queue */ 1046246145Shselasky 1047246145Shselasky pm2->pm_num = up->up_msg_num; 1048246145Shselasky TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry); 1049246145Shselasky 1050246145Shselasky return (pm2); 1051246145Shselasky} 1052246145Shselasky 1053246145Shselasky/*------------------------------------------------------------------------* 1054246145Shselasky * usb_proc_is_gone 1055246145Shselasky * 1056246145Shselasky * Return values: 1057246145Shselasky * 0: USB process is running 1058246145Shselasky * Else: USB process is tearing down 1059246145Shselasky *------------------------------------------------------------------------*/ 1060246145Shselaskyuint8_t 1061246145Shselaskyusb_proc_is_gone(struct usb_process *up) 1062246145Shselasky{ 1063246145Shselasky return (0); 1064246145Shselasky} 1065246145Shselasky 1066246145Shselasky/*------------------------------------------------------------------------* 1067246145Shselasky * usb_proc_mwait 1068246145Shselasky * 1069246145Shselasky * This function will return when the USB process message pointed to 1070246145Shselasky * by "pm" is no longer on a queue. This function must be called 1071246145Shselasky * having "usb_proc_mtx" locked. 1072246145Shselasky *------------------------------------------------------------------------*/ 1073246145Shselaskyvoid 1074246145Shselaskyusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1) 1075246145Shselasky{ 1076246145Shselasky struct usb_proc_msg *pm0 = _pm0; 1077246145Shselasky struct usb_proc_msg *pm1 = _pm1; 1078246145Shselasky 1079246145Shselasky /* Just remove the messages from the queue. */ 1080246145Shselasky if (pm0->pm_qentry.tqe_prev) { 1081246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry); 1082246145Shselasky pm0->pm_qentry.tqe_prev = NULL; 1083246145Shselasky } 1084246145Shselasky if (pm1->pm_qentry.tqe_prev) { 1085246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry); 1086246145Shselasky pm1->pm_qentry.tqe_prev = NULL; 1087246145Shselasky } 1088246145Shselasky} 1089246145Shselasky 1090246145Shselasky/*------------------------------------------------------------------------* 1091246145Shselasky * SYSTEM attach 1092246145Shselasky *------------------------------------------------------------------------*/ 1093246145Shselasky 1094246145Shselaskystatic device_method_t pci_methods[] = { 1095246145Shselasky DEVMETHOD_END 1096246145Shselasky}; 1097246145Shselasky 1098246145Shselaskystatic driver_t pci_driver = { 1099246145Shselasky .name = "pci", 1100246145Shselasky .methods = pci_methods, 1101246145Shselasky}; 1102246145Shselasky 1103246145Shselaskystatic devclass_t pci_devclass; 1104246145Shselasky 1105246145ShselaskyDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0); 1106246145Shselasky 1107246145Shselaskystatic const char *usb_pci_devices[] = { 1108246145Shselasky#ifdef USB_PROBE_LIST 1109246145Shselasky USB_PROBE_LIST 1110246145Shselasky#endif 1111246145Shselasky}; 1112246145Shselasky 1113246145Shselasky#define USB_PCI_USB_MAX (sizeof(usb_pci_devices) / sizeof(void *)) 1114246145Shselasky 1115246145Shselaskystatic device_t usb_pci_dev[USB_PCI_USB_MAX]; 1116246145Shselasky 1117246145Shselaskystatic void 1118246145Shselaskyusb_pci_mod_load(void *arg) 1119246145Shselasky{ 1120246145Shselasky uint32_t x; 1121246145Shselasky 1122246145Shselasky usb_pci_root = device_add_child(NULL, "pci", -1); 1123246145Shselasky if (usb_pci_root == NULL) 1124246145Shselasky return; 1125246145Shselasky 1126246145Shselasky for (x = 0; x != USB_PCI_USB_MAX; x++) { 1127246145Shselasky usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1); 1128246145Shselasky if (usb_pci_dev[x] == NULL) 1129246145Shselasky continue; 1130246145Shselasky if (device_probe_and_attach(usb_pci_dev[x])) { 1131246145Shselasky device_printf(usb_pci_dev[x], 1132246145Shselasky "WARNING: Probe and attach failed!\n"); 1133246145Shselasky } 1134246145Shselasky } 1135246145Shselasky} 1136246145ShselaskySYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0); 1137246145Shselasky 1138246145Shselaskystatic void 1139246145Shselaskyusb_pci_mod_unload(void *arg) 1140246145Shselasky{ 1141246145Shselasky uint32_t x; 1142246145Shselasky 1143246145Shselasky for (x = 0; x != USB_PCI_USB_MAX; x++) { 1144246145Shselasky if (usb_pci_dev[x]) { 1145246145Shselasky device_detach(usb_pci_dev[x]); 1146246145Shselasky device_delete_child(usb_pci_root, usb_pci_dev[x]); 1147246145Shselasky } 1148246145Shselasky } 1149246145Shselasky if (usb_pci_root) 1150246145Shselasky device_delete_child(NULL, usb_pci_root); 1151246145Shselasky} 1152246145ShselaskySYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0); 1153246145Shselasky 1154246145Shselasky/*------------------------------------------------------------------------* 1155246145Shselasky * MALLOC API 1156246145Shselasky *------------------------------------------------------------------------*/ 1157246145Shselasky 1158246145Shselasky#define USB_POOL_ALIGN 8 1159246145Shselasky 1160246145Shselaskystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN); 1161246145Shselaskystatic uint32_t usb_pool_rem = USB_POOL_SIZE; 1162246145Shselaskystatic uint32_t usb_pool_entries; 1163246145Shselasky 1164246145Shselaskystruct malloc_hdr { 1165246145Shselasky TAILQ_ENTRY(malloc_hdr) entry; 1166246145Shselasky uint32_t size; 1167246145Shselasky} __aligned(USB_POOL_ALIGN); 1168246145Shselasky 1169246145Shselaskystatic TAILQ_HEAD(, malloc_hdr) malloc_head = 1170246145Shselasky TAILQ_HEAD_INITIALIZER(malloc_head); 1171246145Shselasky 1172246145Shselaskyvoid * 1173246145Shselaskyusb_malloc(unsigned long size) 1174246145Shselasky{ 1175246145Shselasky struct malloc_hdr *hdr; 1176246145Shselasky 1177246145Shselasky size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1); 1178246145Shselasky size += sizeof(struct malloc_hdr); 1179246145Shselasky 1180246145Shselasky TAILQ_FOREACH(hdr, &malloc_head, entry) { 1181246145Shselasky if (hdr->size == size) 1182246145Shselasky break; 1183246145Shselasky } 1184246145Shselasky 1185246145Shselasky if (hdr) { 1186246145Shselasky printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1187246145Shselasky (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1188246145Shselasky 1189246145Shselasky TAILQ_REMOVE(&malloc_head, hdr, entry); 1190246145Shselasky memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1191246145Shselasky return (hdr + 1); 1192246145Shselasky } 1193246145Shselasky if (usb_pool_rem >= size) { 1194246145Shselasky hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem); 1195246145Shselasky hdr->size = size; 1196246145Shselasky 1197246145Shselasky usb_pool_rem -= size; 1198246145Shselasky usb_pool_entries++; 1199246145Shselasky 1200246145Shselasky printf("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1201246145Shselasky (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1202246145Shselasky 1203246145Shselasky memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1204246145Shselasky return (hdr + 1); 1205246145Shselasky } 1206246145Shselasky return (NULL); 1207246145Shselasky} 1208246145Shselasky 1209246145Shselaskyvoid 1210246145Shselaskyusb_free(void *arg) 1211246145Shselasky{ 1212246145Shselasky struct malloc_hdr *hdr; 1213246145Shselasky 1214246145Shselasky if (arg == NULL) 1215246145Shselasky return; 1216246145Shselasky 1217246145Shselasky hdr = arg; 1218246145Shselasky hdr--; 1219246145Shselasky 1220246145Shselasky TAILQ_INSERT_TAIL(&malloc_head, hdr, entry); 1221246145Shselasky} 1222246145Shselasky 1223246145Shselaskychar * 1224246145Shselaskyusb_strdup(const char *str) 1225246145Shselasky{ 1226246145Shselasky char *tmp; 1227246145Shselasky int len; 1228246145Shselasky 1229246145Shselasky len = 1 + strlen(str); 1230246145Shselasky 1231246145Shselasky tmp = usb_malloc(len); 1232246145Shselasky if (tmp == NULL) 1233246145Shselasky return (NULL); 1234246145Shselasky 1235246145Shselasky memcpy(tmp, str, len); 1236246145Shselasky return (tmp); 1237246145Shselasky} 1238