1246145Shselasky/* $FreeBSD: stable/11/stand/kshim/bsd_kernel.c 315221 2017-03-14 02:06:03Z pfg $ */ 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; 38291405Szbbint (*bus_alloc_resource_any_cb)(struct resource *res, device_t dev, 39291405Szbb int type, int *rid, unsigned int flags); 40291405Szbbint (*ofw_bus_status_ok_cb)(device_t dev); 41291405Szbbint (*ofw_bus_is_compatible_cb)(device_t dev, char *name); 42246145Shselasky 43246145Shselaskystatic void 44246145Shselaskymtx_system_init(void *arg) 45246145Shselasky{ 46246145Shselasky mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE); 47246145Shselasky} 48246145ShselaskySYSINIT(mtx_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, mtx_system_init, NULL); 49246145Shselasky 50294547Swmaint 51294547Swmabus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 52294547Swma bus_size_t boundary, bus_addr_t lowaddr, 53294547Swma bus_addr_t highaddr, bus_dma_filter_t *filter, 54294547Swma void *filterarg, bus_size_t maxsize, int nsegments, 55294547Swma bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, 56294547Swma void *lockfuncarg, bus_dma_tag_t *dmat) 57294547Swma{ 58294547Swma struct bus_dma_tag *ret; 59294547Swma 60294547Swma ret = malloc(sizeof(struct bus_dma_tag), XXX, XXX); 61294547Swma if (*dmat == NULL) 62294547Swma return (ENOMEM); 63294547Swma ret->alignment = alignment; 64294547Swma ret->maxsize = maxsize; 65294547Swma 66294547Swma *dmat = ret; 67294547Swma 68294547Swma return (0); 69294547Swma} 70294547Swma 71294547Swmaint 72294547Swmabus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, 73294547Swma bus_dmamap_t *mapp) 74294547Swma{ 75294547Swma void *addr; 76294547Swma 77294547Swma addr = malloc(dmat->maxsize + dmat->alignment, XXX, XXX); 78315221Spfg if (addr == NULL) 79294547Swma return (ENOMEM); 80294547Swma 81294547Swma *mapp = addr; 82294547Swma addr = (void*)(((uintptr_t)addr + dmat->alignment - 1) & ~(dmat->alignment - 1)); 83294547Swma 84294547Swma *vaddr = addr; 85294547Swma return (0); 86294547Swma} 87294547Swma 88294547Swmaint 89294547Swmabus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 90294547Swma bus_size_t buflen, bus_dmamap_callback_t *callback, 91294547Swma void *callback_arg, int flags) 92294547Swma{ 93294547Swma bus_dma_segment_t segs[1]; 94294547Swma 95294547Swma segs[0].ds_addr = (uintptr_t)buf; 96294547Swma segs[0].ds_len = buflen; 97294547Swma 98294547Swma (*callback)(callback_arg, segs, 1, 0); 99294547Swma 100294547Swma return (0); 101294547Swma} 102294547Swma 103294547Swmavoid 104294547Swmabus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) 105294547Swma{ 106294547Swma 107294547Swma free(map, XXX); 108294547Swma} 109294547Swma 110294547Swmaint 111294547Swmabus_dma_tag_destroy(bus_dma_tag_t dmat) 112294547Swma{ 113294547Swma 114294547Swma free(dmat, XXX); 115294547Swma return (0); 116294547Swma} 117294547Swma 118291405Szbbstruct resource * 119291405Szbbbus_alloc_resource_any(device_t dev, int type, int *rid, unsigned int flags) 120291405Szbb{ 121291405Szbb struct resource *res; 122291405Szbb int ret = EINVAL; 123291405Szbb 124291405Szbb res = malloc(sizeof(*res), XXX, XXX); 125291405Szbb if (res == NULL) 126291405Szbb return (NULL); 127291405Szbb 128291405Szbb res->__r_i = malloc(sizeof(struct resource_i), XXX, XXX); 129291405Szbb if (res->__r_i == NULL) { 130291405Szbb free(res, XXX); 131291405Szbb return (NULL); 132291405Szbb } 133291405Szbb 134291405Szbb if (bus_alloc_resource_any_cb != NULL) 135291405Szbb ret = (*bus_alloc_resource_any_cb)(res, dev, type, rid, flags); 136291405Szbb if (ret == 0) 137291405Szbb return (res); 138291405Szbb 139291405Szbb free(res->__r_i, XXX); 140291405Szbb free(res, XXX); 141291405Szbb return (NULL); 142291405Szbb} 143291405Szbb 144291405Szbbint 145291405Szbbbus_alloc_resources(device_t dev, struct resource_spec *rs, 146291405Szbb struct resource **res) 147291405Szbb{ 148291405Szbb int i; 149291405Szbb 150291405Szbb for (i = 0; rs[i].type != -1; i++) 151291405Szbb res[i] = NULL; 152291405Szbb for (i = 0; rs[i].type != -1; i++) { 153291405Szbb res[i] = bus_alloc_resource_any(dev, 154291405Szbb rs[i].type, &rs[i].rid, rs[i].flags); 155291405Szbb if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) { 156291405Szbb bus_release_resources(dev, rs, res); 157291405Szbb return (ENXIO); 158291405Szbb } 159291405Szbb } 160291405Szbb return (0); 161291405Szbb} 162291405Szbb 163246145Shselaskyvoid 164291405Szbbbus_release_resources(device_t dev, const struct resource_spec *rs, 165291405Szbb struct resource **res) 166291405Szbb{ 167291405Szbb int i; 168291405Szbb 169291405Szbb for (i = 0; rs[i].type != -1; i++) 170291405Szbb if (res[i] != NULL) { 171291405Szbb bus_release_resource( 172291405Szbb dev, rs[i].type, rs[i].rid, res[i]); 173291405Szbb res[i] = NULL; 174291405Szbb } 175291405Szbb} 176291405Szbb 177291405Szbbint 178291405Szbbbus_setup_intr(device_t dev, struct resource *r, int flags, 179291405Szbb driver_filter_t filter, driver_intr_t handler, void *arg, void **cookiep) 180291405Szbb{ 181291405Szbb 182291405Szbb dev->dev_irq_filter = filter; 183291405Szbb dev->dev_irq_fn = handler; 184291405Szbb dev->dev_irq_arg = arg; 185291405Szbb 186291405Szbb return (0); 187291405Szbb} 188291405Szbb 189291405Szbbint 190291405Szbbbus_teardown_intr(device_t dev, struct resource *r, void *cookie) 191291405Szbb{ 192291405Szbb 193291405Szbb dev->dev_irq_filter = NULL; 194291405Szbb dev->dev_irq_fn = NULL; 195291405Szbb dev->dev_irq_arg = NULL; 196291405Szbb 197291405Szbb return (0); 198291405Szbb} 199291405Szbb 200291405Szbbint 201291405Szbbbus_release_resource(device_t dev, int type, int rid, struct resource *r) 202291405Szbb{ 203291405Szbb /* Resource releasing is not supported */ 204291405Szbb return (EINVAL); 205291405Szbb} 206291405Szbb 207291405Szbbint 208291405Szbbbus_generic_attach(device_t dev) 209291405Szbb{ 210291405Szbb device_t child; 211291405Szbb 212291405Szbb TAILQ_FOREACH(child, &dev->dev_children, dev_link) { 213291405Szbb device_probe_and_attach(child); 214291405Szbb } 215291405Szbb 216291405Szbb return (0); 217291405Szbb} 218291405Szbb 219291405Szbbbus_space_tag_t 220291405Szbbrman_get_bustag(struct resource *r) 221291405Szbb{ 222291405Szbb 223291405Szbb return (r->r_bustag); 224291405Szbb} 225291405Szbb 226291405Szbbbus_space_handle_t 227291405Szbbrman_get_bushandle(struct resource *r) 228291405Szbb{ 229291405Szbb 230291405Szbb return (r->r_bushandle); 231291405Szbb} 232291405Szbb 233291405Szbbu_long 234291405Szbbrman_get_size(struct resource *r) 235291405Szbb{ 236291405Szbb 237291405Szbb return (r->__r_i->r_end - r->__r_i->r_start + 1); 238291405Szbb} 239291405Szbb 240291405Szbbint 241291405Szbbofw_bus_status_okay(device_t dev) 242291405Szbb{ 243291405Szbb if (ofw_bus_status_ok_cb == NULL) 244291405Szbb return (0); 245291405Szbb 246291405Szbb return ((*ofw_bus_status_ok_cb)(dev)); 247291405Szbb} 248291405Szbb 249291405Szbbint 250291405Szbbofw_bus_is_compatible(device_t dev, char *name) 251291405Szbb{ 252291405Szbb if (ofw_bus_is_compatible_cb == NULL) 253291405Szbb return (0); 254291405Szbb 255291405Szbb return ((*ofw_bus_is_compatible_cb)(dev, name)); 256291405Szbb} 257291405Szbb 258291405Szbbvoid 259246145Shselaskymtx_init(struct mtx *mtx, const char *name, const char *type, int opt) 260246145Shselasky{ 261246145Shselasky mtx->owned = 0; 262246145Shselasky mtx->parent = mtx; 263246145Shselasky} 264246145Shselasky 265246145Shselaskyvoid 266246145Shselaskymtx_lock(struct mtx *mtx) 267246145Shselasky{ 268246145Shselasky mtx = mtx->parent; 269246145Shselasky mtx->owned++; 270246145Shselasky} 271246145Shselasky 272246145Shselaskyvoid 273246145Shselaskymtx_unlock(struct mtx *mtx) 274246145Shselasky{ 275246145Shselasky mtx = mtx->parent; 276246145Shselasky mtx->owned--; 277246145Shselasky} 278246145Shselasky 279246145Shselaskyint 280246145Shselaskymtx_owned(struct mtx *mtx) 281246145Shselasky{ 282246145Shselasky mtx = mtx->parent; 283246145Shselasky return (mtx->owned != 0); 284246145Shselasky} 285246145Shselasky 286246145Shselaskyvoid 287246145Shselaskymtx_destroy(struct mtx *mtx) 288246145Shselasky{ 289246145Shselasky /* NOP */ 290246145Shselasky} 291246145Shselasky 292246145Shselasky/*------------------------------------------------------------------------* 293246145Shselasky * Implementation of shared/exclusive mutex API 294246145Shselasky *------------------------------------------------------------------------*/ 295246145Shselasky 296246145Shselaskyvoid 297246145Shselaskysx_init_flags(struct sx *sx, const char *name, int flags) 298246145Shselasky{ 299246145Shselasky sx->owned = 0; 300246145Shselasky} 301246145Shselasky 302246145Shselaskyvoid 303246145Shselaskysx_destroy(struct sx *sx) 304246145Shselasky{ 305246145Shselasky /* NOP */ 306246145Shselasky} 307246145Shselasky 308246145Shselaskyvoid 309246145Shselaskysx_xlock(struct sx *sx) 310246145Shselasky{ 311246145Shselasky sx->owned++; 312246145Shselasky} 313246145Shselasky 314246145Shselaskyvoid 315246145Shselaskysx_xunlock(struct sx *sx) 316246145Shselasky{ 317246145Shselasky sx->owned--; 318246145Shselasky} 319246145Shselasky 320246145Shselaskyint 321246145Shselaskysx_xlocked(struct sx *sx) 322246145Shselasky{ 323246145Shselasky return (sx->owned != 0); 324246145Shselasky} 325246145Shselasky 326246145Shselasky/*------------------------------------------------------------------------* 327246145Shselasky * Implementaiton of condition variable API 328246145Shselasky *------------------------------------------------------------------------*/ 329246145Shselasky 330246145Shselaskyvoid 331246145Shselaskycv_init(struct cv *cv, const char *desc) 332246145Shselasky{ 333246145Shselasky cv->sleeping = 0; 334246145Shselasky} 335246145Shselasky 336246145Shselaskyvoid 337246145Shselaskycv_destroy(struct cv *cv) 338246145Shselasky{ 339246145Shselasky /* NOP */ 340246145Shselasky} 341246145Shselasky 342246145Shselaskyvoid 343246145Shselaskycv_wait(struct cv *cv, struct mtx *mtx) 344246145Shselasky{ 345246145Shselasky cv_timedwait(cv, mtx, -1); 346246145Shselasky} 347246145Shselasky 348246145Shselaskyint 349246145Shselaskycv_timedwait(struct cv *cv, struct mtx *mtx, int timo) 350246145Shselasky{ 351246145Shselasky int start = ticks; 352246145Shselasky int delta; 353291403Szbb int time = 0; 354246145Shselasky 355246145Shselasky if (cv->sleeping) 356246145Shselasky return (EWOULDBLOCK); /* not allowed */ 357246145Shselasky 358246145Shselasky cv->sleeping = 1; 359246145Shselasky 360246145Shselasky while (cv->sleeping) { 361246145Shselasky if (timo >= 0) { 362246145Shselasky delta = ticks - start; 363246145Shselasky if (delta >= timo || delta < 0) 364246145Shselasky break; 365246145Shselasky } 366246145Shselasky mtx_unlock(mtx); 367246145Shselasky 368246145Shselasky usb_idle(); 369246145Shselasky 370291403Szbb if (++time >= (1000000 / hz)) { 371291403Szbb time = 0; 372291403Szbb callout_process(1); 373291403Szbb } 374291403Szbb 375291403Szbb /* Sleep for 1 us */ 376291403Szbb delay(1); 377291403Szbb 378246145Shselasky mtx_lock(mtx); 379246145Shselasky } 380246145Shselasky 381246145Shselasky if (cv->sleeping) { 382246145Shselasky cv->sleeping = 0; 383246145Shselasky return (EWOULDBLOCK); /* not allowed */ 384246145Shselasky } 385246145Shselasky return (0); 386246145Shselasky} 387246145Shselasky 388246145Shselaskyvoid 389246145Shselaskycv_signal(struct cv *cv) 390246145Shselasky{ 391246145Shselasky cv->sleeping = 0; 392246145Shselasky} 393246145Shselasky 394246145Shselaskyvoid 395246145Shselaskycv_broadcast(struct cv *cv) 396246145Shselasky{ 397246145Shselasky cv->sleeping = 0; 398246145Shselasky} 399246145Shselasky 400246145Shselasky/*------------------------------------------------------------------------* 401246145Shselasky * Implementation of callout API 402246145Shselasky *------------------------------------------------------------------------*/ 403246145Shselasky 404246145Shselaskystatic void callout_proc_msg(struct usb_proc_msg *); 405246145Shselasky 406246145Shselaskyvolatile int ticks = 0; 407246145Shselasky 408246145Shselaskystatic LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout); 409246145Shselasky 410246145Shselaskystatic struct mtx mtx_callout; 411246145Shselaskystatic struct usb_proc_msg callout_msg[2]; 412246145Shselasky 413246145Shselaskystatic void 414246145Shselaskycallout_system_init(void *arg) 415246145Shselasky{ 416246145Shselasky mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE); 417246145Shselasky 418246145Shselasky callout_msg[0].pm_callback = &callout_proc_msg; 419246145Shselasky callout_msg[1].pm_callback = &callout_proc_msg; 420246145Shselasky} 421246145ShselaskySYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL); 422246145Shselasky 423246145Shselaskystatic void 424246145Shselaskycallout_callback(struct callout *c) 425246145Shselasky{ 426246145Shselasky mtx_lock(c->mtx); 427246145Shselasky 428246145Shselasky mtx_lock(&mtx_callout); 429246145Shselasky if (c->entry.le_prev != NULL) { 430246145Shselasky LIST_REMOVE(c, entry); 431246145Shselasky c->entry.le_prev = NULL; 432246145Shselasky } 433246145Shselasky mtx_unlock(&mtx_callout); 434246145Shselasky 435306255Shselasky if (c->c_func != NULL) 436306255Shselasky (c->c_func) (c->c_arg); 437246145Shselasky 438246145Shselasky if (!(c->flags & CALLOUT_RETURNUNLOCKED)) 439246145Shselasky mtx_unlock(c->mtx); 440246145Shselasky} 441246145Shselasky 442246145Shselaskyvoid 443246145Shselaskycallout_process(int timeout) 444246145Shselasky{ 445246145Shselasky ticks += timeout; 446246145Shselasky usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]); 447246145Shselasky} 448246145Shselasky 449246145Shselaskystatic void 450246145Shselaskycallout_proc_msg(struct usb_proc_msg *pmsg) 451246145Shselasky{ 452246145Shselasky struct callout *c; 453246145Shselasky int delta; 454246145Shselasky 455246145Shselaskyrepeat: 456246145Shselasky mtx_lock(&mtx_callout); 457246145Shselasky 458246145Shselasky LIST_FOREACH(c, &head_callout, entry) { 459246145Shselasky 460246145Shselasky delta = c->timeout - ticks; 461246145Shselasky if (delta < 0) { 462246145Shselasky mtx_unlock(&mtx_callout); 463246145Shselasky 464246145Shselasky callout_callback(c); 465246145Shselasky 466246145Shselasky goto repeat; 467246145Shselasky } 468246145Shselasky } 469246145Shselasky mtx_unlock(&mtx_callout); 470246145Shselasky} 471246145Shselasky 472246145Shselaskyvoid 473246145Shselaskycallout_init_mtx(struct callout *c, struct mtx *mtx, int flags) 474246145Shselasky{ 475246145Shselasky memset(c, 0, sizeof(*c)); 476246145Shselasky 477246145Shselasky if (mtx == NULL) 478246145Shselasky mtx = &Giant; 479246145Shselasky 480246145Shselasky c->mtx = mtx; 481246145Shselasky c->flags = (flags & CALLOUT_RETURNUNLOCKED); 482246145Shselasky} 483246145Shselasky 484246145Shselaskyvoid 485246145Shselaskycallout_reset(struct callout *c, int to_ticks, 486246145Shselasky void (*func) (void *), void *arg) 487246145Shselasky{ 488246145Shselasky callout_stop(c); 489246145Shselasky 490306255Shselasky c->c_func = func; 491306255Shselasky c->c_arg = arg; 492246145Shselasky c->timeout = ticks + to_ticks; 493246145Shselasky 494246145Shselasky mtx_lock(&mtx_callout); 495246145Shselasky LIST_INSERT_HEAD(&head_callout, c, entry); 496246145Shselasky mtx_unlock(&mtx_callout); 497246145Shselasky} 498246145Shselasky 499246145Shselaskyvoid 500246145Shselaskycallout_stop(struct callout *c) 501246145Shselasky{ 502246145Shselasky mtx_lock(&mtx_callout); 503246145Shselasky 504246145Shselasky if (c->entry.le_prev != NULL) { 505246145Shselasky LIST_REMOVE(c, entry); 506246145Shselasky c->entry.le_prev = NULL; 507246145Shselasky } 508246145Shselasky mtx_unlock(&mtx_callout); 509246145Shselasky 510306255Shselasky c->c_func = NULL; 511306255Shselasky c->c_arg = NULL; 512246145Shselasky} 513246145Shselasky 514246145Shselaskyvoid 515246145Shselaskycallout_drain(struct callout *c) 516246145Shselasky{ 517246145Shselasky if (c->mtx == NULL) 518246145Shselasky return; /* not initialised */ 519246145Shselasky 520246145Shselasky mtx_lock(c->mtx); 521246145Shselasky callout_stop(c); 522246145Shselasky mtx_unlock(c->mtx); 523246145Shselasky} 524246145Shselasky 525246145Shselaskyint 526246145Shselaskycallout_pending(struct callout *c) 527246145Shselasky{ 528246145Shselasky int retval; 529246145Shselasky 530246145Shselasky mtx_lock(&mtx_callout); 531246145Shselasky retval = (c->entry.le_prev != NULL); 532246145Shselasky mtx_unlock(&mtx_callout); 533246145Shselasky 534246145Shselasky return (retval); 535246145Shselasky} 536246145Shselasky 537246145Shselasky/*------------------------------------------------------------------------* 538246145Shselasky * Implementation of device API 539246145Shselasky *------------------------------------------------------------------------*/ 540246145Shselasky 541246145Shselaskystatic const char unknown_string[] = { "unknown" }; 542246145Shselasky 543246145Shselaskystatic TAILQ_HEAD(, module_data) module_head = 544246145Shselasky TAILQ_HEAD_INITIALIZER(module_head); 545246145Shselasky 546246145Shselaskystatic uint8_t 547246145Shselaskydevclass_equal(const char *a, const char *b) 548246145Shselasky{ 549246145Shselasky char ta, tb; 550246145Shselasky 551246145Shselasky if (a == b) 552246145Shselasky return (1); 553246145Shselasky 554246145Shselasky while (1) { 555246145Shselasky ta = *a; 556246145Shselasky tb = *b; 557246145Shselasky if (ta != tb) 558246145Shselasky return (0); 559246145Shselasky if (ta == 0) 560246145Shselasky break; 561246145Shselasky a++; 562246145Shselasky b++; 563246145Shselasky } 564246145Shselasky return (1); 565246145Shselasky} 566246145Shselasky 567246145Shselaskyint 568246145Shselaskybus_generic_resume(device_t dev) 569246145Shselasky{ 570246145Shselasky return (0); 571246145Shselasky} 572246145Shselasky 573246145Shselaskyint 574246145Shselaskybus_generic_shutdown(device_t dev) 575246145Shselasky{ 576246145Shselasky return (0); 577246145Shselasky} 578246145Shselasky 579246145Shselaskyint 580246145Shselaskybus_generic_suspend(device_t dev) 581246145Shselasky{ 582246145Shselasky return (0); 583246145Shselasky} 584246145Shselasky 585246145Shselaskyint 586246145Shselaskybus_generic_print_child(device_t dev, device_t child) 587246145Shselasky{ 588246145Shselasky return (0); 589246145Shselasky} 590246145Shselasky 591246145Shselaskyvoid 592246145Shselaskybus_generic_driver_added(device_t dev, driver_t *driver) 593246145Shselasky{ 594246145Shselasky return; 595246145Shselasky} 596246145Shselasky 597246145Shselaskydevice_t 598246145Shselaskydevice_get_parent(device_t dev) 599246145Shselasky{ 600246145Shselasky return (dev ? dev->dev_parent : NULL); 601246145Shselasky} 602246145Shselasky 603246145Shselaskyvoid 604266396Shselaskydevice_set_interrupt(device_t dev, driver_filter_t *filter, 605266396Shselasky driver_intr_t *fn, void *arg) 606246145Shselasky{ 607266396Shselasky dev->dev_irq_filter = filter; 608246145Shselasky dev->dev_irq_fn = fn; 609246145Shselasky dev->dev_irq_arg = arg; 610246145Shselasky} 611246145Shselasky 612246145Shselaskyvoid 613246145Shselaskydevice_run_interrupts(device_t parent) 614246145Shselasky{ 615246145Shselasky device_t child; 616246145Shselasky 617246145Shselasky if (parent == NULL) 618246145Shselasky return; 619246145Shselasky 620246145Shselasky TAILQ_FOREACH(child, &parent->dev_children, dev_link) { 621266396Shselasky int status; 622266396Shselasky if (child->dev_irq_filter != NULL) 623266396Shselasky status = child->dev_irq_filter(child->dev_irq_arg); 624266396Shselasky else 625266396Shselasky status = FILTER_SCHEDULE_THREAD; 626266396Shselasky 627266396Shselasky if (status == FILTER_SCHEDULE_THREAD) { 628266396Shselasky if (child->dev_irq_fn != NULL) 629266396Shselasky (child->dev_irq_fn) (child->dev_irq_arg); 630266396Shselasky } 631246145Shselasky } 632246145Shselasky} 633246145Shselasky 634246145Shselaskyvoid 635246145Shselaskydevice_set_ivars(device_t dev, void *ivars) 636246145Shselasky{ 637246145Shselasky dev->dev_aux = ivars; 638246145Shselasky} 639246145Shselasky 640246145Shselaskyvoid * 641246145Shselaskydevice_get_ivars(device_t dev) 642246145Shselasky{ 643246145Shselasky return (dev ? dev->dev_aux : NULL); 644246145Shselasky} 645246145Shselasky 646246145Shselaskyint 647246145Shselaskydevice_get_unit(device_t dev) 648246145Shselasky{ 649246145Shselasky return (dev ? dev->dev_unit : 0); 650246145Shselasky} 651246145Shselasky 652246145Shselaskyint 653246145Shselaskybus_generic_detach(device_t dev) 654246145Shselasky{ 655246145Shselasky device_t child; 656246145Shselasky int error; 657246145Shselasky 658246145Shselasky if (!dev->dev_attached) 659246145Shselasky return (EBUSY); 660246145Shselasky 661246145Shselasky TAILQ_FOREACH(child, &dev->dev_children, dev_link) { 662246145Shselasky if ((error = device_detach(child)) != 0) 663246145Shselasky return (error); 664246145Shselasky } 665246145Shselasky return (0); 666246145Shselasky} 667246145Shselasky 668246145Shselaskyconst char * 669246145Shselaskydevice_get_nameunit(device_t dev) 670246145Shselasky{ 671246145Shselasky if (dev && dev->dev_nameunit[0]) 672246145Shselasky return (dev->dev_nameunit); 673246145Shselasky 674246145Shselasky return (unknown_string); 675246145Shselasky} 676246145Shselasky 677246145Shselaskystatic uint8_t 678246145Shselaskydevclass_create(devclass_t *dc_pp) 679246145Shselasky{ 680246145Shselasky if (dc_pp == NULL) { 681246145Shselasky return (1); 682246145Shselasky } 683246145Shselasky if (dc_pp[0] == NULL) { 684246145Shselasky dc_pp[0] = malloc(sizeof(**(dc_pp)), 685246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 686246145Shselasky 687246145Shselasky if (dc_pp[0] == NULL) { 688246145Shselasky return (1); 689246145Shselasky } 690246145Shselasky } 691246145Shselasky return (0); 692246145Shselasky} 693246145Shselasky 694246145Shselaskystatic const struct module_data * 695246145Shselaskydevclass_find_create(const char *classname) 696246145Shselasky{ 697246145Shselasky const struct module_data *mod; 698246145Shselasky 699246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 700246145Shselasky if (devclass_equal(mod->mod_name, classname)) { 701246145Shselasky if (devclass_create(mod->devclass_pp)) { 702246145Shselasky continue; 703246145Shselasky } 704246145Shselasky return (mod); 705246145Shselasky } 706246145Shselasky } 707246145Shselasky return (NULL); 708246145Shselasky} 709246145Shselasky 710246145Shselaskystatic uint8_t 711246145Shselaskydevclass_add_device(const struct module_data *mod, device_t dev) 712246145Shselasky{ 713246145Shselasky device_t *pp_dev; 714246145Shselasky device_t *end; 715246145Shselasky uint8_t unit; 716246145Shselasky 717246145Shselasky pp_dev = mod->devclass_pp[0]->dev_list; 718246145Shselasky end = pp_dev + DEVCLASS_MAXUNIT; 719246145Shselasky unit = 0; 720246145Shselasky 721246145Shselasky while (pp_dev != end) { 722246145Shselasky if (*pp_dev == NULL) { 723246145Shselasky *pp_dev = dev; 724246145Shselasky dev->dev_unit = unit; 725246145Shselasky dev->dev_module = mod; 726246145Shselasky snprintf(dev->dev_nameunit, 727246145Shselasky sizeof(dev->dev_nameunit), 728246145Shselasky "%s%d", device_get_name(dev), unit); 729246145Shselasky return (0); 730246145Shselasky } 731246145Shselasky pp_dev++; 732246145Shselasky unit++; 733246145Shselasky } 734246145Shselasky DPRINTF("Could not add device to devclass.\n"); 735246145Shselasky return (1); 736246145Shselasky} 737246145Shselasky 738246145Shselaskystatic void 739246145Shselaskydevclass_delete_device(const struct module_data *mod, device_t dev) 740246145Shselasky{ 741246145Shselasky if (mod == NULL) { 742246145Shselasky return; 743246145Shselasky } 744246145Shselasky mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL; 745246145Shselasky dev->dev_module = NULL; 746246145Shselasky} 747246145Shselasky 748246145Shselaskystatic device_t 749246145Shselaskymake_device(device_t parent, const char *name) 750246145Shselasky{ 751246145Shselasky device_t dev = NULL; 752246145Shselasky const struct module_data *mod = NULL; 753246145Shselasky 754246145Shselasky if (name) { 755246145Shselasky 756246145Shselasky mod = devclass_find_create(name); 757246145Shselasky 758246145Shselasky if (!mod) { 759246145Shselasky 760246145Shselasky DPRINTF("%s:%d:%s: can't find device " 761246145Shselasky "class %s\n", __FILE__, __LINE__, 762246145Shselasky __FUNCTION__, name); 763246145Shselasky 764246145Shselasky goto done; 765246145Shselasky } 766246145Shselasky } 767246145Shselasky dev = malloc(sizeof(*dev), 768246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 769246145Shselasky 770246145Shselasky if (dev == NULL) 771246145Shselasky goto done; 772246145Shselasky 773246145Shselasky dev->dev_parent = parent; 774246145Shselasky TAILQ_INIT(&dev->dev_children); 775246145Shselasky 776246145Shselasky if (name) { 777246145Shselasky dev->dev_fixed_class = 1; 778246145Shselasky if (devclass_add_device(mod, dev)) { 779246145Shselasky goto error; 780246145Shselasky } 781246145Shselasky } 782246145Shselaskydone: 783246145Shselasky return (dev); 784246145Shselasky 785246145Shselaskyerror: 786246145Shselasky if (dev) { 787246145Shselasky free(dev, M_DEVBUF); 788246145Shselasky } 789246145Shselasky return (NULL); 790246145Shselasky} 791246145Shselasky 792246145Shselaskydevice_t 793246145Shselaskydevice_add_child(device_t dev, const char *name, int unit) 794246145Shselasky{ 795246145Shselasky device_t child; 796246145Shselasky 797246145Shselasky if (unit != -1) { 798246145Shselasky device_printf(dev, "Unit is not -1\n"); 799246145Shselasky } 800246145Shselasky child = make_device(dev, name); 801246145Shselasky if (child == NULL) { 802246145Shselasky device_printf(dev, "Could not add child '%s'\n", name); 803246145Shselasky goto done; 804246145Shselasky } 805246145Shselasky if (dev == NULL) { 806246145Shselasky /* no parent */ 807246145Shselasky goto done; 808246145Shselasky } 809246145Shselasky TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link); 810246145Shselaskydone: 811246145Shselasky return (child); 812246145Shselasky} 813246145Shselasky 814246145Shselaskyint 815246145Shselaskydevice_delete_child(device_t dev, device_t child) 816246145Shselasky{ 817246145Shselasky int error = 0; 818246145Shselasky device_t grandchild; 819246145Shselasky 820308401Shselasky /* detach parent before deleting children, if any */ 821308401Shselasky error = device_detach(child); 822308401Shselasky if (error) 823308401Shselasky goto done; 824246145Shselasky 825308401Shselasky /* remove children second */ 826246145Shselasky while ((grandchild = TAILQ_FIRST(&child->dev_children))) { 827246145Shselasky error = device_delete_child(child, grandchild); 828246145Shselasky if (error) { 829246145Shselasky device_printf(dev, "Error deleting child!\n"); 830246145Shselasky goto done; 831246145Shselasky } 832246145Shselasky } 833246145Shselasky 834246145Shselasky devclass_delete_device(child->dev_module, child); 835246145Shselasky 836246145Shselasky if (dev != NULL) { 837246145Shselasky /* remove child from parent */ 838246145Shselasky TAILQ_REMOVE(&dev->dev_children, child, dev_link); 839246145Shselasky } 840246145Shselasky free(child, M_DEVBUF); 841246145Shselasky 842246145Shselaskydone: 843246145Shselasky return (error); 844246145Shselasky} 845246145Shselasky 846246145Shselaskyint 847246145Shselaskydevice_delete_children(device_t dev) 848246145Shselasky{ 849246145Shselasky device_t child; 850246145Shselasky int error = 0; 851246145Shselasky 852246145Shselasky while ((child = TAILQ_FIRST(&dev->dev_children))) { 853246145Shselasky error = device_delete_child(dev, child); 854246145Shselasky if (error) { 855246145Shselasky device_printf(dev, "Error deleting child!\n"); 856246145Shselasky break; 857246145Shselasky } 858246145Shselasky } 859246145Shselasky return (error); 860246145Shselasky} 861246145Shselasky 862246145Shselaskyvoid 863246145Shselaskydevice_quiet(device_t dev) 864246145Shselasky{ 865246145Shselasky dev->dev_quiet = 1; 866246145Shselasky} 867246145Shselasky 868246145Shselaskyconst char * 869246145Shselaskydevice_get_desc(device_t dev) 870246145Shselasky{ 871246145Shselasky if (dev) 872246145Shselasky return &(dev->dev_desc[0]); 873246145Shselasky return (unknown_string); 874246145Shselasky} 875246145Shselasky 876246145Shselaskystatic int 877246145Shselaskydefault_method(void) 878246145Shselasky{ 879246145Shselasky /* do nothing */ 880246145Shselasky DPRINTF("Default method called\n"); 881246145Shselasky return (0); 882246145Shselasky} 883246145Shselasky 884246145Shselaskyvoid * 885246145Shselaskydevice_get_method(device_t dev, const char *what) 886246145Shselasky{ 887246145Shselasky const struct device_method *mtod; 888246145Shselasky 889246145Shselasky mtod = dev->dev_module->driver->methods; 890246145Shselasky while (mtod->func != NULL) { 891246145Shselasky if (devclass_equal(mtod->desc, what)) { 892246145Shselasky return (mtod->func); 893246145Shselasky } 894246145Shselasky mtod++; 895246145Shselasky } 896246145Shselasky return ((void *)&default_method); 897246145Shselasky} 898246145Shselasky 899246145Shselaskyconst char * 900246145Shselaskydevice_get_name(device_t dev) 901246145Shselasky{ 902246145Shselasky if (dev == NULL) 903246145Shselasky return (unknown_string); 904246145Shselasky 905246145Shselasky return (dev->dev_module->driver->name); 906246145Shselasky} 907246145Shselasky 908246145Shselaskystatic int 909246145Shselaskydevice_allocate_softc(device_t dev) 910246145Shselasky{ 911246145Shselasky const struct module_data *mod; 912246145Shselasky 913246145Shselasky mod = dev->dev_module; 914246145Shselasky 915246145Shselasky if ((dev->dev_softc_alloc == 0) && 916246145Shselasky (mod->driver->size != 0)) { 917246145Shselasky dev->dev_sc = malloc(mod->driver->size, 918246145Shselasky M_DEVBUF, M_WAITOK | M_ZERO); 919246145Shselasky 920246145Shselasky if (dev->dev_sc == NULL) 921246145Shselasky return (ENOMEM); 922246145Shselasky 923246145Shselasky dev->dev_softc_alloc = 1; 924246145Shselasky } 925246145Shselasky return (0); 926246145Shselasky} 927246145Shselasky 928246145Shselaskyint 929246145Shselaskydevice_probe_and_attach(device_t dev) 930246145Shselasky{ 931246145Shselasky const struct module_data *mod; 932246145Shselasky const char *bus_name_parent; 933246145Shselasky 934246145Shselasky bus_name_parent = device_get_name(device_get_parent(dev)); 935246145Shselasky 936246145Shselasky if (dev->dev_attached) 937246145Shselasky return (0); /* fail-safe */ 938246145Shselasky 939246145Shselasky if (dev->dev_fixed_class) { 940246145Shselasky 941246145Shselasky mod = dev->dev_module; 942246145Shselasky 943246145Shselasky if (DEVICE_PROBE(dev) <= 0) { 944246145Shselasky 945246145Shselasky if (device_allocate_softc(dev) == 0) { 946246145Shselasky 947246145Shselasky if (DEVICE_ATTACH(dev) == 0) { 948246145Shselasky /* success */ 949246145Shselasky dev->dev_attached = 1; 950246145Shselasky return (0); 951246145Shselasky } 952246145Shselasky } 953246145Shselasky } 954246145Shselasky device_detach(dev); 955246145Shselasky 956246145Shselasky goto error; 957246145Shselasky } 958246145Shselasky /* 959246145Shselasky * Else find a module for our device, if any 960246145Shselasky */ 961246145Shselasky 962246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 963246145Shselasky if (devclass_equal(mod->bus_name, bus_name_parent)) { 964246145Shselasky if (devclass_create(mod->devclass_pp)) { 965246145Shselasky continue; 966246145Shselasky } 967246145Shselasky if (devclass_add_device(mod, dev)) { 968246145Shselasky continue; 969246145Shselasky } 970246145Shselasky if (DEVICE_PROBE(dev) <= 0) { 971246145Shselasky 972246145Shselasky if (device_allocate_softc(dev) == 0) { 973246145Shselasky 974246145Shselasky if (DEVICE_ATTACH(dev) == 0) { 975246145Shselasky /* success */ 976246145Shselasky dev->dev_attached = 1; 977246145Shselasky return (0); 978246145Shselasky } 979246145Shselasky } 980246145Shselasky } 981246145Shselasky /* else try next driver */ 982246145Shselasky 983246145Shselasky device_detach(dev); 984246145Shselasky } 985246145Shselasky } 986246145Shselasky 987246145Shselaskyerror: 988246145Shselasky return (ENODEV); 989246145Shselasky} 990246145Shselasky 991246145Shselaskyint 992246145Shselaskydevice_detach(device_t dev) 993246145Shselasky{ 994246145Shselasky const struct module_data *mod = dev->dev_module; 995246145Shselasky int error; 996246145Shselasky 997246145Shselasky if (dev->dev_attached) { 998246145Shselasky 999246145Shselasky error = DEVICE_DETACH(dev); 1000246145Shselasky if (error) { 1001246145Shselasky return error; 1002246145Shselasky } 1003246145Shselasky dev->dev_attached = 0; 1004246145Shselasky } 1005246145Shselasky device_set_softc(dev, NULL); 1006246145Shselasky 1007246145Shselasky if (dev->dev_fixed_class == 0) 1008246145Shselasky devclass_delete_device(mod, dev); 1009246145Shselasky 1010246145Shselasky return (0); 1011246145Shselasky} 1012246145Shselasky 1013246145Shselaskyvoid 1014246145Shselaskydevice_set_softc(device_t dev, void *softc) 1015246145Shselasky{ 1016246145Shselasky if (dev->dev_softc_alloc) { 1017246145Shselasky free(dev->dev_sc, M_DEVBUF); 1018246145Shselasky dev->dev_sc = NULL; 1019246145Shselasky } 1020246145Shselasky dev->dev_sc = softc; 1021246145Shselasky dev->dev_softc_alloc = 0; 1022246145Shselasky} 1023246145Shselasky 1024246145Shselaskyvoid * 1025246145Shselaskydevice_get_softc(device_t dev) 1026246145Shselasky{ 1027246145Shselasky if (dev == NULL) 1028246145Shselasky return (NULL); 1029246145Shselasky 1030246145Shselasky return (dev->dev_sc); 1031246145Shselasky} 1032246145Shselasky 1033246145Shselaskyint 1034246145Shselaskydevice_is_attached(device_t dev) 1035246145Shselasky{ 1036246145Shselasky return (dev->dev_attached); 1037246145Shselasky} 1038246145Shselasky 1039246145Shselaskyvoid 1040246145Shselaskydevice_set_desc(device_t dev, const char *desc) 1041246145Shselasky{ 1042246145Shselasky snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc); 1043246145Shselasky} 1044246145Shselasky 1045246145Shselaskyvoid 1046246145Shselaskydevice_set_desc_copy(device_t dev, const char *desc) 1047246145Shselasky{ 1048246145Shselasky device_set_desc(dev, desc); 1049246145Shselasky} 1050246145Shselasky 1051246145Shselaskyvoid * 1052246145Shselaskydevclass_get_softc(devclass_t dc, int unit) 1053246145Shselasky{ 1054246145Shselasky return (device_get_softc(devclass_get_device(dc, unit))); 1055246145Shselasky} 1056246145Shselasky 1057246145Shselaskyint 1058246145Shselaskydevclass_get_maxunit(devclass_t dc) 1059246145Shselasky{ 1060246145Shselasky int max_unit = 0; 1061246145Shselasky 1062246145Shselasky if (dc) { 1063246145Shselasky max_unit = DEVCLASS_MAXUNIT; 1064246145Shselasky while (max_unit--) { 1065246145Shselasky if (dc->dev_list[max_unit]) { 1066246145Shselasky break; 1067246145Shselasky } 1068246145Shselasky } 1069246145Shselasky max_unit++; 1070246145Shselasky } 1071246145Shselasky return (max_unit); 1072246145Shselasky} 1073246145Shselasky 1074246145Shselaskydevice_t 1075246145Shselaskydevclass_get_device(devclass_t dc, int unit) 1076246145Shselasky{ 1077246145Shselasky return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ? 1078246145Shselasky NULL : dc->dev_list[unit]); 1079246145Shselasky} 1080246145Shselasky 1081246145Shselaskydevclass_t 1082246145Shselaskydevclass_find(const char *classname) 1083246145Shselasky{ 1084246145Shselasky const struct module_data *mod; 1085246145Shselasky 1086246145Shselasky TAILQ_FOREACH(mod, &module_head, entry) { 1087291405Szbb if (devclass_equal(mod->driver->name, classname)) 1088246145Shselasky return (mod->devclass_pp[0]); 1089246145Shselasky } 1090246145Shselasky return (NULL); 1091246145Shselasky} 1092246145Shselasky 1093246145Shselaskyvoid 1094246145Shselaskymodule_register(void *data) 1095246145Shselasky{ 1096246145Shselasky struct module_data *mdata = data; 1097246145Shselasky 1098246145Shselasky TAILQ_INSERT_TAIL(&module_head, mdata, entry); 1099246145Shselasky} 1100246145Shselasky 1101246145Shselasky/*------------------------------------------------------------------------* 1102246145Shselasky * System startup 1103246145Shselasky *------------------------------------------------------------------------*/ 1104246145Shselasky 1105246145Shselaskystatic void 1106246145Shselaskysysinit_run(const void **ppdata) 1107246145Shselasky{ 1108246145Shselasky const struct sysinit *psys; 1109246145Shselasky 1110246145Shselasky while ((psys = *ppdata) != NULL) { 1111246145Shselasky (psys->func) (psys->data); 1112246145Shselasky ppdata++; 1113246145Shselasky } 1114246145Shselasky} 1115246145Shselasky 1116246145Shselasky/*------------------------------------------------------------------------* 1117246145Shselasky * USB process API 1118246145Shselasky *------------------------------------------------------------------------*/ 1119246145Shselasky 1120246145Shselaskystatic int usb_do_process(struct usb_process *); 1121246145Shselaskystatic int usb_proc_level = -1; 1122246145Shselaskystatic struct mtx usb_proc_mtx; 1123246145Shselasky 1124246145Shselaskyvoid 1125246145Shselaskyusb_idle(void) 1126246145Shselasky{ 1127246145Shselasky int old_level = usb_proc_level; 1128246145Shselasky int old_giant = Giant.owned; 1129246145Shselasky int worked; 1130246145Shselasky 1131246145Shselasky device_run_interrupts(usb_pci_root); 1132246145Shselasky 1133246145Shselasky do { 1134246145Shselasky worked = 0; 1135246145Shselasky Giant.owned = 0; 1136246145Shselasky 1137246145Shselasky while (++usb_proc_level < USB_PROC_MAX) 1138246145Shselasky worked |= usb_do_process(usb_process + usb_proc_level); 1139246145Shselasky 1140246145Shselasky usb_proc_level = old_level; 1141246145Shselasky Giant.owned = old_giant; 1142246145Shselasky 1143246145Shselasky } while (worked); 1144246145Shselasky} 1145246145Shselasky 1146246145Shselaskyvoid 1147246145Shselaskyusb_init(void) 1148246145Shselasky{ 1149246145Shselasky sysinit_run(sysinit_data); 1150246145Shselasky} 1151246145Shselasky 1152246145Shselaskyvoid 1153246145Shselaskyusb_uninit(void) 1154246145Shselasky{ 1155246145Shselasky sysinit_run(sysuninit_data); 1156246145Shselasky} 1157246145Shselasky 1158246145Shselaskystatic void 1159246145Shselaskyusb_process_init_sub(struct usb_process *up) 1160246145Shselasky{ 1161246145Shselasky TAILQ_INIT(&up->up_qhead); 1162246145Shselasky 1163246145Shselasky cv_init(&up->up_cv, "-"); 1164246145Shselasky cv_init(&up->up_drain, "usbdrain"); 1165246145Shselasky 1166246145Shselasky up->up_mtx = &usb_proc_mtx; 1167246145Shselasky} 1168246145Shselasky 1169246145Shselaskystatic void 1170246145Shselaskyusb_process_init(void *arg) 1171246145Shselasky{ 1172246145Shselasky uint8_t x; 1173246145Shselasky 1174246145Shselasky mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE); 1175246145Shselasky 1176246145Shselasky for (x = 0; x != USB_PROC_MAX; x++) 1177246145Shselasky usb_process_init_sub(&usb_process[x]); 1178246145Shselasky 1179246145Shselasky} 1180246145ShselaskySYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL); 1181246145Shselasky 1182246145Shselaskystatic int 1183246145Shselaskyusb_do_process(struct usb_process *up) 1184246145Shselasky{ 1185246145Shselasky struct usb_proc_msg *pm; 1186246145Shselasky int worked = 0; 1187246145Shselasky 1188246145Shselasky mtx_lock(&usb_proc_mtx); 1189246145Shselasky 1190246145Shselaskyrepeat: 1191246145Shselasky pm = TAILQ_FIRST(&up->up_qhead); 1192246145Shselasky 1193246145Shselasky if (pm != NULL) { 1194246145Shselasky 1195246145Shselasky worked = 1; 1196246145Shselasky 1197246145Shselasky (pm->pm_callback) (pm); 1198246145Shselasky 1199246145Shselasky if (pm == TAILQ_FIRST(&up->up_qhead)) { 1200246145Shselasky /* nothing changed */ 1201246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); 1202246145Shselasky pm->pm_qentry.tqe_prev = NULL; 1203246145Shselasky } 1204246145Shselasky goto repeat; 1205246145Shselasky } 1206246145Shselasky mtx_unlock(&usb_proc_mtx); 1207246145Shselasky 1208246145Shselasky return (worked); 1209246145Shselasky} 1210246145Shselasky 1211246145Shselaskyvoid * 1212246145Shselaskyusb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1) 1213246145Shselasky{ 1214246145Shselasky struct usb_proc_msg *pm0 = _pm0; 1215246145Shselasky struct usb_proc_msg *pm1 = _pm1; 1216246145Shselasky struct usb_proc_msg *pm2; 1217246145Shselasky usb_size_t d; 1218246145Shselasky uint8_t t; 1219246145Shselasky 1220246145Shselasky t = 0; 1221246145Shselasky 1222246145Shselasky if (pm0->pm_qentry.tqe_prev) { 1223246145Shselasky t |= 1; 1224246145Shselasky } 1225246145Shselasky if (pm1->pm_qentry.tqe_prev) { 1226246145Shselasky t |= 2; 1227246145Shselasky } 1228246145Shselasky if (t == 0) { 1229246145Shselasky /* 1230246145Shselasky * No entries are queued. Queue "pm0" and use the existing 1231246145Shselasky * message number. 1232246145Shselasky */ 1233246145Shselasky pm2 = pm0; 1234246145Shselasky } else if (t == 1) { 1235246145Shselasky /* Check if we need to increment the message number. */ 1236246145Shselasky if (pm0->pm_num == up->up_msg_num) { 1237246145Shselasky up->up_msg_num++; 1238246145Shselasky } 1239246145Shselasky pm2 = pm1; 1240246145Shselasky } else if (t == 2) { 1241246145Shselasky /* Check if we need to increment the message number. */ 1242246145Shselasky if (pm1->pm_num == up->up_msg_num) { 1243246145Shselasky up->up_msg_num++; 1244246145Shselasky } 1245246145Shselasky pm2 = pm0; 1246246145Shselasky } else if (t == 3) { 1247246145Shselasky /* 1248246145Shselasky * Both entries are queued. Re-queue the entry closest to 1249246145Shselasky * the end. 1250246145Shselasky */ 1251246145Shselasky d = (pm1->pm_num - pm0->pm_num); 1252246145Shselasky 1253246145Shselasky /* Check sign after subtraction */ 1254246145Shselasky if (d & 0x80000000) { 1255246145Shselasky pm2 = pm0; 1256246145Shselasky } else { 1257246145Shselasky pm2 = pm1; 1258246145Shselasky } 1259246145Shselasky 1260246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry); 1261246145Shselasky } else { 1262246145Shselasky pm2 = NULL; /* panic - should not happen */ 1263246145Shselasky } 1264246145Shselasky 1265246145Shselasky /* Put message last on queue */ 1266246145Shselasky 1267246145Shselasky pm2->pm_num = up->up_msg_num; 1268246145Shselasky TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry); 1269246145Shselasky 1270246145Shselasky return (pm2); 1271246145Shselasky} 1272246145Shselasky 1273246145Shselasky/*------------------------------------------------------------------------* 1274246145Shselasky * usb_proc_is_gone 1275246145Shselasky * 1276246145Shselasky * Return values: 1277246145Shselasky * 0: USB process is running 1278246145Shselasky * Else: USB process is tearing down 1279246145Shselasky *------------------------------------------------------------------------*/ 1280246145Shselaskyuint8_t 1281246145Shselaskyusb_proc_is_gone(struct usb_process *up) 1282246145Shselasky{ 1283246145Shselasky return (0); 1284246145Shselasky} 1285246145Shselasky 1286246145Shselasky/*------------------------------------------------------------------------* 1287246145Shselasky * usb_proc_mwait 1288246145Shselasky * 1289246145Shselasky * This function will return when the USB process message pointed to 1290246145Shselasky * by "pm" is no longer on a queue. This function must be called 1291246145Shselasky * having "usb_proc_mtx" locked. 1292246145Shselasky *------------------------------------------------------------------------*/ 1293246145Shselaskyvoid 1294246145Shselaskyusb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1) 1295246145Shselasky{ 1296246145Shselasky struct usb_proc_msg *pm0 = _pm0; 1297246145Shselasky struct usb_proc_msg *pm1 = _pm1; 1298246145Shselasky 1299246145Shselasky /* Just remove the messages from the queue. */ 1300246145Shselasky if (pm0->pm_qentry.tqe_prev) { 1301246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry); 1302246145Shselasky pm0->pm_qentry.tqe_prev = NULL; 1303246145Shselasky } 1304246145Shselasky if (pm1->pm_qentry.tqe_prev) { 1305246145Shselasky TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry); 1306246145Shselasky pm1->pm_qentry.tqe_prev = NULL; 1307246145Shselasky } 1308246145Shselasky} 1309246145Shselasky 1310246145Shselasky/*------------------------------------------------------------------------* 1311246145Shselasky * SYSTEM attach 1312246145Shselasky *------------------------------------------------------------------------*/ 1313246145Shselasky 1314266882Shselasky#ifdef USB_PCI_PROBE_LIST 1315246145Shselaskystatic device_method_t pci_methods[] = { 1316246145Shselasky DEVMETHOD_END 1317246145Shselasky}; 1318246145Shselasky 1319246145Shselaskystatic driver_t pci_driver = { 1320246145Shselasky .name = "pci", 1321246145Shselasky .methods = pci_methods, 1322246145Shselasky}; 1323246145Shselasky 1324246145Shselaskystatic devclass_t pci_devclass; 1325246145Shselasky 1326246145ShselaskyDRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0); 1327246145Shselasky 1328246145Shselaskystatic const char *usb_pci_devices[] = { 1329266882Shselasky USB_PCI_PROBE_LIST 1330246145Shselasky}; 1331246145Shselasky 1332246145Shselasky#define USB_PCI_USB_MAX (sizeof(usb_pci_devices) / sizeof(void *)) 1333246145Shselasky 1334246145Shselaskystatic device_t usb_pci_dev[USB_PCI_USB_MAX]; 1335246145Shselasky 1336246145Shselaskystatic void 1337246145Shselaskyusb_pci_mod_load(void *arg) 1338246145Shselasky{ 1339246145Shselasky uint32_t x; 1340246145Shselasky 1341246145Shselasky usb_pci_root = device_add_child(NULL, "pci", -1); 1342246145Shselasky if (usb_pci_root == NULL) 1343246145Shselasky return; 1344246145Shselasky 1345246145Shselasky for (x = 0; x != USB_PCI_USB_MAX; x++) { 1346246145Shselasky usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1); 1347246145Shselasky if (usb_pci_dev[x] == NULL) 1348246145Shselasky continue; 1349246145Shselasky if (device_probe_and_attach(usb_pci_dev[x])) { 1350246145Shselasky device_printf(usb_pci_dev[x], 1351246145Shselasky "WARNING: Probe and attach failed!\n"); 1352246145Shselasky } 1353246145Shselasky } 1354246145Shselasky} 1355246145ShselaskySYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0); 1356246145Shselasky 1357246145Shselaskystatic void 1358246145Shselaskyusb_pci_mod_unload(void *arg) 1359246145Shselasky{ 1360246145Shselasky uint32_t x; 1361246145Shselasky 1362246145Shselasky for (x = 0; x != USB_PCI_USB_MAX; x++) { 1363246145Shselasky if (usb_pci_dev[x]) { 1364246145Shselasky device_detach(usb_pci_dev[x]); 1365246145Shselasky device_delete_child(usb_pci_root, usb_pci_dev[x]); 1366246145Shselasky } 1367246145Shselasky } 1368246145Shselasky if (usb_pci_root) 1369246145Shselasky device_delete_child(NULL, usb_pci_root); 1370246145Shselasky} 1371246145ShselaskySYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0); 1372266882Shselasky#endif 1373246145Shselasky 1374246145Shselasky/*------------------------------------------------------------------------* 1375246145Shselasky * MALLOC API 1376246145Shselasky *------------------------------------------------------------------------*/ 1377246145Shselasky 1378266882Shselasky#ifndef HAVE_MALLOC 1379246145Shselasky#define USB_POOL_ALIGN 8 1380246145Shselasky 1381246145Shselaskystatic uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN); 1382246145Shselaskystatic uint32_t usb_pool_rem = USB_POOL_SIZE; 1383246145Shselaskystatic uint32_t usb_pool_entries; 1384246145Shselasky 1385246145Shselaskystruct malloc_hdr { 1386246145Shselasky TAILQ_ENTRY(malloc_hdr) entry; 1387246145Shselasky uint32_t size; 1388246145Shselasky} __aligned(USB_POOL_ALIGN); 1389246145Shselasky 1390246145Shselaskystatic TAILQ_HEAD(, malloc_hdr) malloc_head = 1391246145Shselasky TAILQ_HEAD_INITIALIZER(malloc_head); 1392246145Shselasky 1393246145Shselaskyvoid * 1394246145Shselaskyusb_malloc(unsigned long size) 1395246145Shselasky{ 1396246145Shselasky struct malloc_hdr *hdr; 1397246145Shselasky 1398246145Shselasky size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1); 1399246145Shselasky size += sizeof(struct malloc_hdr); 1400246145Shselasky 1401246145Shselasky TAILQ_FOREACH(hdr, &malloc_head, entry) { 1402246145Shselasky if (hdr->size == size) 1403246145Shselasky break; 1404246145Shselasky } 1405246145Shselasky 1406246145Shselasky if (hdr) { 1407266882Shselasky DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1408246145Shselasky (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1409246145Shselasky 1410246145Shselasky TAILQ_REMOVE(&malloc_head, hdr, entry); 1411246145Shselasky memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1412246145Shselasky return (hdr + 1); 1413246145Shselasky } 1414246145Shselasky if (usb_pool_rem >= size) { 1415246145Shselasky hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem); 1416246145Shselasky hdr->size = size; 1417246145Shselasky 1418246145Shselasky usb_pool_rem -= size; 1419246145Shselasky usb_pool_entries++; 1420246145Shselasky 1421266882Shselasky DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1422246145Shselasky (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1423246145Shselasky 1424246145Shselasky memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1425246145Shselasky return (hdr + 1); 1426246145Shselasky } 1427246145Shselasky return (NULL); 1428246145Shselasky} 1429246145Shselasky 1430246145Shselaskyvoid 1431246145Shselaskyusb_free(void *arg) 1432246145Shselasky{ 1433246145Shselasky struct malloc_hdr *hdr; 1434246145Shselasky 1435246145Shselasky if (arg == NULL) 1436246145Shselasky return; 1437246145Shselasky 1438246145Shselasky hdr = arg; 1439246145Shselasky hdr--; 1440246145Shselasky 1441246145Shselasky TAILQ_INSERT_TAIL(&malloc_head, hdr, entry); 1442246145Shselasky} 1443266882Shselasky#endif 1444246145Shselasky 1445246145Shselaskychar * 1446246145Shselaskyusb_strdup(const char *str) 1447246145Shselasky{ 1448246145Shselasky char *tmp; 1449246145Shselasky int len; 1450246145Shselasky 1451246145Shselasky len = 1 + strlen(str); 1452246145Shselasky 1453266882Shselasky tmp = malloc(len,XXX,XXX); 1454246145Shselasky if (tmp == NULL) 1455246145Shselasky return (NULL); 1456246145Shselasky 1457246145Shselasky memcpy(tmp, str, len); 1458246145Shselasky return (tmp); 1459246145Shselasky} 1460