1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 2013 Hans Petter Selasky. All rights reserved. 3ca987d46SWarner Losh * 4ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 5ca987d46SWarner Losh * modification, are permitted provided that the following conditions 6ca987d46SWarner Losh * are met: 7ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 8ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 9ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 10ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 11ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 12ca987d46SWarner Losh * 13ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23ca987d46SWarner Losh * SUCH DAMAGE. 24ca987d46SWarner Losh */ 25ca987d46SWarner Losh 26ca987d46SWarner Losh #include <bsd_global.h> 27ca987d46SWarner Losh 28ca987d46SWarner Losh struct usb_process usb_process[USB_PROC_MAX]; 29ca987d46SWarner Losh 30ca987d46SWarner Losh static device_t usb_pci_root; 31ca987d46SWarner Losh 32ca987d46SWarner Losh int (*bus_alloc_resource_any_cb)(struct resource *res, device_t dev, 33ca987d46SWarner Losh int type, int *rid, unsigned int flags); 34ca987d46SWarner Losh int (*ofw_bus_status_ok_cb)(device_t dev); 35ca987d46SWarner Losh int (*ofw_bus_is_compatible_cb)(device_t dev, char *name); 36ca987d46SWarner Losh 3734602358SHans Petter Selasky /*------------------------------------------------------------------------* 3834602358SHans Petter Selasky * Implementation of busdma API 3934602358SHans Petter Selasky *------------------------------------------------------------------------*/ 40ca987d46SWarner Losh int 41ca987d46SWarner Losh bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 42ca987d46SWarner Losh bus_size_t boundary, bus_addr_t lowaddr, 43ca987d46SWarner Losh bus_addr_t highaddr, bus_dma_filter_t *filter, 44ca987d46SWarner Losh void *filterarg, bus_size_t maxsize, int nsegments, 45ca987d46SWarner Losh bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, 46ca987d46SWarner Losh void *lockfuncarg, bus_dma_tag_t *dmat) 47ca987d46SWarner Losh { 48ca987d46SWarner Losh struct bus_dma_tag *ret; 49ca987d46SWarner Losh 50ca987d46SWarner Losh ret = malloc(sizeof(struct bus_dma_tag), XXX, XXX); 51ca987d46SWarner Losh if (*dmat == NULL) 52ca987d46SWarner Losh return (ENOMEM); 53ca987d46SWarner Losh ret->alignment = alignment; 54ca987d46SWarner Losh ret->maxsize = maxsize; 55ca987d46SWarner Losh 56ca987d46SWarner Losh *dmat = ret; 57ca987d46SWarner Losh 58ca987d46SWarner Losh return (0); 59ca987d46SWarner Losh } 60ca987d46SWarner Losh 61ca987d46SWarner Losh int 62ca987d46SWarner Losh bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, 63ca987d46SWarner Losh bus_dmamap_t *mapp) 64ca987d46SWarner Losh { 65ca987d46SWarner Losh void *addr; 66ca987d46SWarner Losh 67ca987d46SWarner Losh addr = malloc(dmat->maxsize + dmat->alignment, XXX, XXX); 68ca987d46SWarner Losh if (addr == NULL) 69ca987d46SWarner Losh return (ENOMEM); 70ca987d46SWarner Losh 71ca987d46SWarner Losh *mapp = addr; 72ca987d46SWarner Losh addr = (void*)(((uintptr_t)addr + dmat->alignment - 1) & ~(dmat->alignment - 1)); 73ca987d46SWarner Losh 74ca987d46SWarner Losh *vaddr = addr; 75ca987d46SWarner Losh return (0); 76ca987d46SWarner Losh } 77ca987d46SWarner Losh 78ca987d46SWarner Losh int 79ca987d46SWarner Losh bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 80ca987d46SWarner Losh bus_size_t buflen, bus_dmamap_callback_t *callback, 81ca987d46SWarner Losh void *callback_arg, int flags) 82ca987d46SWarner Losh { 83ca987d46SWarner Losh bus_dma_segment_t segs[1]; 84ca987d46SWarner Losh 85ca987d46SWarner Losh segs[0].ds_addr = (uintptr_t)buf; 86ca987d46SWarner Losh segs[0].ds_len = buflen; 87ca987d46SWarner Losh 88ca987d46SWarner Losh (*callback)(callback_arg, segs, 1, 0); 89ca987d46SWarner Losh 90ca987d46SWarner Losh return (0); 91ca987d46SWarner Losh } 92ca987d46SWarner Losh 93ca987d46SWarner Losh void 94cc7b5411SHans Petter Selasky bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, int flags) 95cc7b5411SHans Petter Selasky { 96cc7b5411SHans Petter Selasky /* Assuming coherent memory */ 97cc7b5411SHans Petter Selasky __asm__ __volatile__("": : :"memory"); 98cc7b5411SHans Petter Selasky } 99cc7b5411SHans Petter Selasky 100cc7b5411SHans Petter Selasky void 101ca987d46SWarner Losh bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) 102ca987d46SWarner Losh { 103ca987d46SWarner Losh 104ca987d46SWarner Losh free(map, XXX); 105ca987d46SWarner Losh } 106ca987d46SWarner Losh 107ca987d46SWarner Losh int 108ca987d46SWarner Losh bus_dma_tag_destroy(bus_dma_tag_t dmat) 109ca987d46SWarner Losh { 110ca987d46SWarner Losh 111ca987d46SWarner Losh free(dmat, XXX); 112ca987d46SWarner Losh return (0); 113ca987d46SWarner Losh } 114ca987d46SWarner Losh 11534602358SHans Petter Selasky /*------------------------------------------------------------------------* 11634602358SHans Petter Selasky * Implementation of resource management API 11734602358SHans Petter Selasky *------------------------------------------------------------------------*/ 11834602358SHans Petter Selasky 119ca987d46SWarner Losh struct resource * 120ca987d46SWarner Losh bus_alloc_resource_any(device_t dev, int type, int *rid, unsigned int flags) 121ca987d46SWarner Losh { 122ca987d46SWarner Losh struct resource *res; 123ca987d46SWarner Losh int ret = EINVAL; 124ca987d46SWarner Losh 125ca987d46SWarner Losh res = malloc(sizeof(*res), XXX, XXX); 126ca987d46SWarner Losh if (res == NULL) 127ca987d46SWarner Losh return (NULL); 128ca987d46SWarner Losh 129ca987d46SWarner Losh res->__r_i = malloc(sizeof(struct resource_i), XXX, XXX); 130ca987d46SWarner Losh if (res->__r_i == NULL) { 131ca987d46SWarner Losh free(res, XXX); 132ca987d46SWarner Losh return (NULL); 133ca987d46SWarner Losh } 134ca987d46SWarner Losh 135ca987d46SWarner Losh if (bus_alloc_resource_any_cb != NULL) 136ca987d46SWarner Losh ret = (*bus_alloc_resource_any_cb)(res, dev, type, rid, flags); 137ca987d46SWarner Losh if (ret == 0) 138ca987d46SWarner Losh return (res); 139ca987d46SWarner Losh 140ca987d46SWarner Losh free(res->__r_i, XXX); 141ca987d46SWarner Losh free(res, XXX); 142ca987d46SWarner Losh return (NULL); 143ca987d46SWarner Losh } 144ca987d46SWarner Losh 145ca987d46SWarner Losh int 146ca987d46SWarner Losh bus_alloc_resources(device_t dev, struct resource_spec *rs, 147ca987d46SWarner Losh struct resource **res) 148ca987d46SWarner Losh { 149ca987d46SWarner Losh int i; 150ca987d46SWarner Losh 151ca987d46SWarner Losh for (i = 0; rs[i].type != -1; i++) 152ca987d46SWarner Losh res[i] = NULL; 153ca987d46SWarner Losh for (i = 0; rs[i].type != -1; i++) { 154ca987d46SWarner Losh res[i] = bus_alloc_resource_any(dev, 155ca987d46SWarner Losh rs[i].type, &rs[i].rid, rs[i].flags); 156ca987d46SWarner Losh if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) { 157ca987d46SWarner Losh bus_release_resources(dev, rs, res); 158ca987d46SWarner Losh return (ENXIO); 159ca987d46SWarner Losh } 160ca987d46SWarner Losh } 161ca987d46SWarner Losh return (0); 162ca987d46SWarner Losh } 163ca987d46SWarner Losh 164ca987d46SWarner Losh void 165ca987d46SWarner Losh bus_release_resources(device_t dev, const struct resource_spec *rs, 166ca987d46SWarner Losh struct resource **res) 167ca987d46SWarner Losh { 168ca987d46SWarner Losh int i; 169ca987d46SWarner Losh 170ca987d46SWarner Losh for (i = 0; rs[i].type != -1; i++) 171ca987d46SWarner Losh if (res[i] != NULL) { 172ca987d46SWarner Losh bus_release_resource( 173ca987d46SWarner Losh dev, rs[i].type, rs[i].rid, res[i]); 174ca987d46SWarner Losh res[i] = NULL; 175ca987d46SWarner Losh } 176ca987d46SWarner Losh } 177ca987d46SWarner Losh 178ca987d46SWarner Losh int 179ca987d46SWarner Losh bus_setup_intr(device_t dev, struct resource *r, int flags, 180ca987d46SWarner Losh driver_filter_t filter, driver_intr_t handler, void *arg, void **cookiep) 181ca987d46SWarner Losh { 182ca987d46SWarner Losh 183ca987d46SWarner Losh dev->dev_irq_filter = filter; 184ca987d46SWarner Losh dev->dev_irq_fn = handler; 185ca987d46SWarner Losh dev->dev_irq_arg = arg; 186ca987d46SWarner Losh 187ca987d46SWarner Losh return (0); 188ca987d46SWarner Losh } 189ca987d46SWarner Losh 190ca987d46SWarner Losh int 191ca987d46SWarner Losh bus_teardown_intr(device_t dev, struct resource *r, void *cookie) 192ca987d46SWarner Losh { 193ca987d46SWarner Losh 194ca987d46SWarner Losh dev->dev_irq_filter = NULL; 195ca987d46SWarner Losh dev->dev_irq_fn = NULL; 196ca987d46SWarner Losh dev->dev_irq_arg = NULL; 197ca987d46SWarner Losh 198ca987d46SWarner Losh return (0); 199ca987d46SWarner Losh } 200ca987d46SWarner Losh 201ca987d46SWarner Losh int 202ca987d46SWarner Losh bus_release_resource(device_t dev, int type, int rid, struct resource *r) 203ca987d46SWarner Losh { 204ca987d46SWarner Losh /* Resource releasing is not supported */ 205ca987d46SWarner Losh return (EINVAL); 206ca987d46SWarner Losh } 207ca987d46SWarner Losh 208*4378bd38SJohn Baldwin void 209*4378bd38SJohn Baldwin bus_attach_children(device_t dev) 210ca987d46SWarner Losh { 211ca987d46SWarner Losh device_t child; 212ca987d46SWarner Losh 213ca987d46SWarner Losh TAILQ_FOREACH(child, &dev->dev_children, dev_link) { 214ca987d46SWarner Losh device_probe_and_attach(child); 215ca987d46SWarner Losh } 216ca987d46SWarner Losh } 217ca987d46SWarner Losh 218ca987d46SWarner Losh bus_space_tag_t 219ca987d46SWarner Losh rman_get_bustag(struct resource *r) 220ca987d46SWarner Losh { 221ca987d46SWarner Losh 222ca987d46SWarner Losh return (r->r_bustag); 223ca987d46SWarner Losh } 224ca987d46SWarner Losh 225ca987d46SWarner Losh bus_space_handle_t 226ca987d46SWarner Losh rman_get_bushandle(struct resource *r) 227ca987d46SWarner Losh { 228ca987d46SWarner Losh 229ca987d46SWarner Losh return (r->r_bushandle); 230ca987d46SWarner Losh } 231ca987d46SWarner Losh 232ca987d46SWarner Losh u_long 233ca987d46SWarner Losh rman_get_size(struct resource *r) 234ca987d46SWarner Losh { 235ca987d46SWarner Losh 236ca987d46SWarner Losh return (r->__r_i->r_end - r->__r_i->r_start + 1); 237ca987d46SWarner Losh } 238ca987d46SWarner Losh 239ca987d46SWarner Losh int 240ca987d46SWarner Losh ofw_bus_status_okay(device_t dev) 241ca987d46SWarner Losh { 242ca987d46SWarner Losh if (ofw_bus_status_ok_cb == NULL) 243ca987d46SWarner Losh return (0); 244ca987d46SWarner Losh 245ca987d46SWarner Losh return ((*ofw_bus_status_ok_cb)(dev)); 246ca987d46SWarner Losh } 247ca987d46SWarner Losh 248ca987d46SWarner Losh int 249ca987d46SWarner Losh ofw_bus_is_compatible(device_t dev, char *name) 250ca987d46SWarner Losh { 251ca987d46SWarner Losh if (ofw_bus_is_compatible_cb == NULL) 252ca987d46SWarner Losh return (0); 253ca987d46SWarner Losh 254ca987d46SWarner Losh return ((*ofw_bus_is_compatible_cb)(dev, name)); 255ca987d46SWarner Losh } 256ca987d46SWarner Losh 25734602358SHans Petter Selasky /*------------------------------------------------------------------------* 25834602358SHans Petter Selasky * Implementation of mutex API 25934602358SHans Petter Selasky *------------------------------------------------------------------------*/ 26034602358SHans Petter Selasky 26134602358SHans Petter Selasky struct mtx Giant; 26234602358SHans Petter Selasky 26334602358SHans Petter Selasky static void 26434602358SHans Petter Selasky mtx_system_init(void *arg) 26534602358SHans Petter Selasky { 26634602358SHans Petter Selasky mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE); 26734602358SHans Petter Selasky } 26834602358SHans Petter Selasky SYSINIT(mtx_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, mtx_system_init, NULL); 26934602358SHans Petter Selasky 270ca987d46SWarner Losh void 271ca987d46SWarner Losh mtx_init(struct mtx *mtx, const char *name, const char *type, int opt) 272ca987d46SWarner Losh { 273ca987d46SWarner Losh mtx->owned = 0; 274ca987d46SWarner Losh mtx->parent = mtx; 275ca987d46SWarner Losh } 276ca987d46SWarner Losh 277ca987d46SWarner Losh void 278ca987d46SWarner Losh mtx_lock(struct mtx *mtx) 279ca987d46SWarner Losh { 280ca987d46SWarner Losh mtx = mtx->parent; 281ca987d46SWarner Losh mtx->owned++; 282ca987d46SWarner Losh } 283ca987d46SWarner Losh 284ca987d46SWarner Losh void 285ca987d46SWarner Losh mtx_unlock(struct mtx *mtx) 286ca987d46SWarner Losh { 287ca987d46SWarner Losh mtx = mtx->parent; 288ca987d46SWarner Losh mtx->owned--; 289ca987d46SWarner Losh } 290ca987d46SWarner Losh 291ca987d46SWarner Losh int 292ca987d46SWarner Losh mtx_owned(struct mtx *mtx) 293ca987d46SWarner Losh { 294ca987d46SWarner Losh mtx = mtx->parent; 295ca987d46SWarner Losh return (mtx->owned != 0); 296ca987d46SWarner Losh } 297ca987d46SWarner Losh 298ca987d46SWarner Losh void 299ca987d46SWarner Losh mtx_destroy(struct mtx *mtx) 300ca987d46SWarner Losh { 301ca987d46SWarner Losh /* NOP */ 302ca987d46SWarner Losh } 303ca987d46SWarner Losh 304ca987d46SWarner Losh /*------------------------------------------------------------------------* 305ca987d46SWarner Losh * Implementation of shared/exclusive mutex API 306ca987d46SWarner Losh *------------------------------------------------------------------------*/ 307ca987d46SWarner Losh 308ca987d46SWarner Losh void 309ca987d46SWarner Losh sx_init_flags(struct sx *sx, const char *name, int flags) 310ca987d46SWarner Losh { 311ca987d46SWarner Losh sx->owned = 0; 312ca987d46SWarner Losh } 313ca987d46SWarner Losh 314ca987d46SWarner Losh void 315ca987d46SWarner Losh sx_destroy(struct sx *sx) 316ca987d46SWarner Losh { 317ca987d46SWarner Losh /* NOP */ 318ca987d46SWarner Losh } 319ca987d46SWarner Losh 320ca987d46SWarner Losh void 321ca987d46SWarner Losh sx_xlock(struct sx *sx) 322ca987d46SWarner Losh { 323ca987d46SWarner Losh sx->owned++; 324ca987d46SWarner Losh } 325ca987d46SWarner Losh 326ca987d46SWarner Losh void 327ca987d46SWarner Losh sx_xunlock(struct sx *sx) 328ca987d46SWarner Losh { 329ca987d46SWarner Losh sx->owned--; 330ca987d46SWarner Losh } 331ca987d46SWarner Losh 332ca987d46SWarner Losh int 333ca987d46SWarner Losh sx_xlocked(struct sx *sx) 334ca987d46SWarner Losh { 335ca987d46SWarner Losh return (sx->owned != 0); 336ca987d46SWarner Losh } 337ca987d46SWarner Losh 338ca987d46SWarner Losh /*------------------------------------------------------------------------* 339ca987d46SWarner Losh * Implementaiton of condition variable API 340ca987d46SWarner Losh *------------------------------------------------------------------------*/ 341ca987d46SWarner Losh 342ca987d46SWarner Losh void 343ca987d46SWarner Losh cv_init(struct cv *cv, const char *desc) 344ca987d46SWarner Losh { 345ca987d46SWarner Losh cv->sleeping = 0; 346ca987d46SWarner Losh } 347ca987d46SWarner Losh 348ca987d46SWarner Losh void 349ca987d46SWarner Losh cv_destroy(struct cv *cv) 350ca987d46SWarner Losh { 351ca987d46SWarner Losh /* NOP */ 352ca987d46SWarner Losh } 353ca987d46SWarner Losh 354ca987d46SWarner Losh void 355ca987d46SWarner Losh cv_wait(struct cv *cv, struct mtx *mtx) 356ca987d46SWarner Losh { 357ca987d46SWarner Losh cv_timedwait(cv, mtx, -1); 358ca987d46SWarner Losh } 359ca987d46SWarner Losh 360ca987d46SWarner Losh int 361ca987d46SWarner Losh cv_timedwait(struct cv *cv, struct mtx *mtx, int timo) 362ca987d46SWarner Losh { 363ca987d46SWarner Losh int start = ticks; 364ca987d46SWarner Losh int delta; 365ca987d46SWarner Losh int time = 0; 366ca987d46SWarner Losh 367ca987d46SWarner Losh if (cv->sleeping) 368ca987d46SWarner Losh return (EWOULDBLOCK); /* not allowed */ 369ca987d46SWarner Losh 370ca987d46SWarner Losh cv->sleeping = 1; 371ca987d46SWarner Losh 372ca987d46SWarner Losh while (cv->sleeping) { 373ca987d46SWarner Losh if (timo >= 0) { 374ca987d46SWarner Losh delta = ticks - start; 375ca987d46SWarner Losh if (delta >= timo || delta < 0) 376ca987d46SWarner Losh break; 377ca987d46SWarner Losh } 378ca987d46SWarner Losh mtx_unlock(mtx); 379ca987d46SWarner Losh 380ca987d46SWarner Losh usb_idle(); 381ca987d46SWarner Losh 382ca987d46SWarner Losh if (++time >= (1000000 / hz)) { 383ca987d46SWarner Losh time = 0; 384ca987d46SWarner Losh callout_process(1); 385ca987d46SWarner Losh } 386ca987d46SWarner Losh 387ca987d46SWarner Losh /* Sleep for 1 us */ 388ca987d46SWarner Losh delay(1); 389ca987d46SWarner Losh 390ca987d46SWarner Losh mtx_lock(mtx); 391ca987d46SWarner Losh } 392ca987d46SWarner Losh 393ca987d46SWarner Losh if (cv->sleeping) { 394ca987d46SWarner Losh cv->sleeping = 0; 395ca987d46SWarner Losh return (EWOULDBLOCK); /* not allowed */ 396ca987d46SWarner Losh } 397ca987d46SWarner Losh return (0); 398ca987d46SWarner Losh } 399ca987d46SWarner Losh 400ca987d46SWarner Losh void 401ca987d46SWarner Losh cv_signal(struct cv *cv) 402ca987d46SWarner Losh { 403ca987d46SWarner Losh cv->sleeping = 0; 404ca987d46SWarner Losh } 405ca987d46SWarner Losh 406ca987d46SWarner Losh void 407ca987d46SWarner Losh cv_broadcast(struct cv *cv) 408ca987d46SWarner Losh { 409ca987d46SWarner Losh cv->sleeping = 0; 410ca987d46SWarner Losh } 411ca987d46SWarner Losh 412ca987d46SWarner Losh /*------------------------------------------------------------------------* 413ca987d46SWarner Losh * Implementation of callout API 414ca987d46SWarner Losh *------------------------------------------------------------------------*/ 415ca987d46SWarner Losh 416ca987d46SWarner Losh static void callout_proc_msg(struct usb_proc_msg *); 417ca987d46SWarner Losh 418ca987d46SWarner Losh volatile int ticks = 0; 419ca987d46SWarner Losh 420ca987d46SWarner Losh static LIST_HEAD(, callout) head_callout = LIST_HEAD_INITIALIZER(&head_callout); 421ca987d46SWarner Losh 422ca987d46SWarner Losh static struct mtx mtx_callout; 423ca987d46SWarner Losh static struct usb_proc_msg callout_msg[2]; 424ca987d46SWarner Losh 425ca987d46SWarner Losh static void 426ca987d46SWarner Losh callout_system_init(void *arg) 427ca987d46SWarner Losh { 428ca987d46SWarner Losh mtx_init(&mtx_callout, "callout-mtx", NULL, MTX_DEF | MTX_RECURSE); 429ca987d46SWarner Losh 430ca987d46SWarner Losh callout_msg[0].pm_callback = &callout_proc_msg; 431ca987d46SWarner Losh callout_msg[1].pm_callback = &callout_proc_msg; 432ca987d46SWarner Losh } 433ca987d46SWarner Losh SYSINIT(callout_system_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, callout_system_init, NULL); 434ca987d46SWarner Losh 435ca987d46SWarner Losh static void 436ca987d46SWarner Losh callout_callback(struct callout *c) 437ca987d46SWarner Losh { 438ca987d46SWarner Losh mtx_lock(c->mtx); 439ca987d46SWarner Losh 440ca987d46SWarner Losh mtx_lock(&mtx_callout); 441ca987d46SWarner Losh if (c->entry.le_prev != NULL) { 442ca987d46SWarner Losh LIST_REMOVE(c, entry); 443ca987d46SWarner Losh c->entry.le_prev = NULL; 444ca987d46SWarner Losh } 445ca987d46SWarner Losh mtx_unlock(&mtx_callout); 446ca987d46SWarner Losh 447ca987d46SWarner Losh if (c->c_func != NULL) 448ca987d46SWarner Losh (c->c_func) (c->c_arg); 449ca987d46SWarner Losh 450ca987d46SWarner Losh if (!(c->flags & CALLOUT_RETURNUNLOCKED)) 451ca987d46SWarner Losh mtx_unlock(c->mtx); 452ca987d46SWarner Losh } 453ca987d46SWarner Losh 454ca987d46SWarner Losh void 455ca987d46SWarner Losh callout_process(int timeout) 456ca987d46SWarner Losh { 457ca987d46SWarner Losh ticks += timeout; 458ca987d46SWarner Losh usb_proc_msignal(usb_process + 2, &callout_msg[0], &callout_msg[1]); 459ca987d46SWarner Losh } 460ca987d46SWarner Losh 461ca987d46SWarner Losh static void 462ca987d46SWarner Losh callout_proc_msg(struct usb_proc_msg *pmsg) 463ca987d46SWarner Losh { 464ca987d46SWarner Losh struct callout *c; 465ca987d46SWarner Losh int delta; 466ca987d46SWarner Losh 467ca987d46SWarner Losh repeat: 468ca987d46SWarner Losh mtx_lock(&mtx_callout); 469ca987d46SWarner Losh 470ca987d46SWarner Losh LIST_FOREACH(c, &head_callout, entry) { 471ca987d46SWarner Losh 472ca987d46SWarner Losh delta = c->timeout - ticks; 473ca987d46SWarner Losh if (delta < 0) { 474ca987d46SWarner Losh mtx_unlock(&mtx_callout); 475ca987d46SWarner Losh 476ca987d46SWarner Losh callout_callback(c); 477ca987d46SWarner Losh 478ca987d46SWarner Losh goto repeat; 479ca987d46SWarner Losh } 480ca987d46SWarner Losh } 481ca987d46SWarner Losh mtx_unlock(&mtx_callout); 482ca987d46SWarner Losh } 483ca987d46SWarner Losh 484ca987d46SWarner Losh void 485ca987d46SWarner Losh callout_init_mtx(struct callout *c, struct mtx *mtx, int flags) 486ca987d46SWarner Losh { 487ca987d46SWarner Losh memset(c, 0, sizeof(*c)); 488ca987d46SWarner Losh 489ca987d46SWarner Losh if (mtx == NULL) 490ca987d46SWarner Losh mtx = &Giant; 491ca987d46SWarner Losh 492ca987d46SWarner Losh c->mtx = mtx; 493ca987d46SWarner Losh c->flags = (flags & CALLOUT_RETURNUNLOCKED); 494ca987d46SWarner Losh } 495ca987d46SWarner Losh 496ca987d46SWarner Losh void 497ca987d46SWarner Losh callout_reset(struct callout *c, int to_ticks, 498ca987d46SWarner Losh void (*func) (void *), void *arg) 499ca987d46SWarner Losh { 500ca987d46SWarner Losh callout_stop(c); 501ca987d46SWarner Losh 502ca987d46SWarner Losh c->c_func = func; 503ca987d46SWarner Losh c->c_arg = arg; 504ca987d46SWarner Losh c->timeout = ticks + to_ticks; 505ca987d46SWarner Losh 506ca987d46SWarner Losh mtx_lock(&mtx_callout); 507ca987d46SWarner Losh LIST_INSERT_HEAD(&head_callout, c, entry); 508ca987d46SWarner Losh mtx_unlock(&mtx_callout); 509ca987d46SWarner Losh } 510ca987d46SWarner Losh 511ca987d46SWarner Losh void 512ca987d46SWarner Losh callout_stop(struct callout *c) 513ca987d46SWarner Losh { 514ca987d46SWarner Losh mtx_lock(&mtx_callout); 515ca987d46SWarner Losh 516ca987d46SWarner Losh if (c->entry.le_prev != NULL) { 517ca987d46SWarner Losh LIST_REMOVE(c, entry); 518ca987d46SWarner Losh c->entry.le_prev = NULL; 519ca987d46SWarner Losh } 520ca987d46SWarner Losh mtx_unlock(&mtx_callout); 521ca987d46SWarner Losh 522ca987d46SWarner Losh c->c_func = NULL; 523ca987d46SWarner Losh c->c_arg = NULL; 524ca987d46SWarner Losh } 525ca987d46SWarner Losh 526ca987d46SWarner Losh void 527ca987d46SWarner Losh callout_drain(struct callout *c) 528ca987d46SWarner Losh { 529ca987d46SWarner Losh if (c->mtx == NULL) 530ca987d46SWarner Losh return; /* not initialised */ 531ca987d46SWarner Losh 532ca987d46SWarner Losh mtx_lock(c->mtx); 533ca987d46SWarner Losh callout_stop(c); 534ca987d46SWarner Losh mtx_unlock(c->mtx); 535ca987d46SWarner Losh } 536ca987d46SWarner Losh 537ca987d46SWarner Losh int 538ca987d46SWarner Losh callout_pending(struct callout *c) 539ca987d46SWarner Losh { 540ca987d46SWarner Losh int retval; 541ca987d46SWarner Losh 542ca987d46SWarner Losh mtx_lock(&mtx_callout); 543ca987d46SWarner Losh retval = (c->entry.le_prev != NULL); 544ca987d46SWarner Losh mtx_unlock(&mtx_callout); 545ca987d46SWarner Losh 546ca987d46SWarner Losh return (retval); 547ca987d46SWarner Losh } 548ca987d46SWarner Losh 549ca987d46SWarner Losh /*------------------------------------------------------------------------* 550ca987d46SWarner Losh * Implementation of device API 551ca987d46SWarner Losh *------------------------------------------------------------------------*/ 552ca987d46SWarner Losh 553ca987d46SWarner Losh static const char unknown_string[] = { "unknown" }; 554ca987d46SWarner Losh 555ca987d46SWarner Losh static TAILQ_HEAD(, module_data) module_head = 556ca987d46SWarner Losh TAILQ_HEAD_INITIALIZER(module_head); 557ca987d46SWarner Losh 558ca987d46SWarner Losh static uint8_t 559ca987d46SWarner Losh devclass_equal(const char *a, const char *b) 560ca987d46SWarner Losh { 561ca987d46SWarner Losh char ta, tb; 562ca987d46SWarner Losh 563ca987d46SWarner Losh if (a == b) 564ca987d46SWarner Losh return (1); 565ca987d46SWarner Losh 566ca987d46SWarner Losh while (1) { 567ca987d46SWarner Losh ta = *a; 568ca987d46SWarner Losh tb = *b; 569ca987d46SWarner Losh if (ta != tb) 570ca987d46SWarner Losh return (0); 571ca987d46SWarner Losh if (ta == 0) 572ca987d46SWarner Losh break; 573ca987d46SWarner Losh a++; 574ca987d46SWarner Losh b++; 575ca987d46SWarner Losh } 576ca987d46SWarner Losh return (1); 577ca987d46SWarner Losh } 578ca987d46SWarner Losh 579ca987d46SWarner Losh int 580ca987d46SWarner Losh bus_generic_resume(device_t dev) 581ca987d46SWarner Losh { 582ca987d46SWarner Losh return (0); 583ca987d46SWarner Losh } 584ca987d46SWarner Losh 585ca987d46SWarner Losh int 586ca987d46SWarner Losh bus_generic_shutdown(device_t dev) 587ca987d46SWarner Losh { 588ca987d46SWarner Losh return (0); 589ca987d46SWarner Losh } 590ca987d46SWarner Losh 591ca987d46SWarner Losh int 592ca987d46SWarner Losh bus_generic_suspend(device_t dev) 593ca987d46SWarner Losh { 594ca987d46SWarner Losh return (0); 595ca987d46SWarner Losh } 596ca987d46SWarner Losh 597ca987d46SWarner Losh int 598ca987d46SWarner Losh bus_generic_print_child(device_t dev, device_t child) 599ca987d46SWarner Losh { 600ca987d46SWarner Losh return (0); 601ca987d46SWarner Losh } 602ca987d46SWarner Losh 603ca987d46SWarner Losh void 604ca987d46SWarner Losh bus_generic_driver_added(device_t dev, driver_t *driver) 605ca987d46SWarner Losh { 606ca987d46SWarner Losh return; 607ca987d46SWarner Losh } 608ca987d46SWarner Losh 609ca987d46SWarner Losh device_t 610ca987d46SWarner Losh device_get_parent(device_t dev) 611ca987d46SWarner Losh { 612ca987d46SWarner Losh return (dev ? dev->dev_parent : NULL); 613ca987d46SWarner Losh } 614ca987d46SWarner Losh 615ca987d46SWarner Losh void 616ca987d46SWarner Losh device_set_interrupt(device_t dev, driver_filter_t *filter, 617ca987d46SWarner Losh driver_intr_t *fn, void *arg) 618ca987d46SWarner Losh { 619ca987d46SWarner Losh dev->dev_irq_filter = filter; 620ca987d46SWarner Losh dev->dev_irq_fn = fn; 621ca987d46SWarner Losh dev->dev_irq_arg = arg; 622ca987d46SWarner Losh } 623ca987d46SWarner Losh 624ca987d46SWarner Losh void 625ca987d46SWarner Losh device_run_interrupts(device_t parent) 626ca987d46SWarner Losh { 627ca987d46SWarner Losh device_t child; 628ca987d46SWarner Losh 629ca987d46SWarner Losh if (parent == NULL) 630ca987d46SWarner Losh return; 631ca987d46SWarner Losh 632ca987d46SWarner Losh TAILQ_FOREACH(child, &parent->dev_children, dev_link) { 633ca987d46SWarner Losh int status; 634ca987d46SWarner Losh if (child->dev_irq_filter != NULL) 635ca987d46SWarner Losh status = child->dev_irq_filter(child->dev_irq_arg); 636ca987d46SWarner Losh else 637ca987d46SWarner Losh status = FILTER_SCHEDULE_THREAD; 638ca987d46SWarner Losh 639ca987d46SWarner Losh if (status == FILTER_SCHEDULE_THREAD) { 640ca987d46SWarner Losh if (child->dev_irq_fn != NULL) 641ca987d46SWarner Losh (child->dev_irq_fn) (child->dev_irq_arg); 642ca987d46SWarner Losh } 643ca987d46SWarner Losh } 644ca987d46SWarner Losh } 645ca987d46SWarner Losh 646ca987d46SWarner Losh void 647ca987d46SWarner Losh device_set_ivars(device_t dev, void *ivars) 648ca987d46SWarner Losh { 649ca987d46SWarner Losh dev->dev_aux = ivars; 650ca987d46SWarner Losh } 651ca987d46SWarner Losh 652ca987d46SWarner Losh void * 653ca987d46SWarner Losh device_get_ivars(device_t dev) 654ca987d46SWarner Losh { 655ca987d46SWarner Losh return (dev ? dev->dev_aux : NULL); 656ca987d46SWarner Losh } 657ca987d46SWarner Losh 658ca987d46SWarner Losh int 659ca987d46SWarner Losh device_get_unit(device_t dev) 660ca987d46SWarner Losh { 661ca987d46SWarner Losh return (dev ? dev->dev_unit : 0); 662ca987d46SWarner Losh } 663ca987d46SWarner Losh 664ca987d46SWarner Losh int 665ca987d46SWarner Losh bus_generic_detach(device_t dev) 666ca987d46SWarner Losh { 667ca987d46SWarner Losh device_t child; 668ca987d46SWarner Losh int error; 669ca987d46SWarner Losh 670ca987d46SWarner Losh if (!dev->dev_attached) 671ca987d46SWarner Losh return (EBUSY); 672ca987d46SWarner Losh 673ca987d46SWarner Losh TAILQ_FOREACH(child, &dev->dev_children, dev_link) { 674ca987d46SWarner Losh if ((error = device_detach(child)) != 0) 675ca987d46SWarner Losh return (error); 676ca987d46SWarner Losh } 677ca987d46SWarner Losh return (0); 678ca987d46SWarner Losh } 679ca987d46SWarner Losh 680ca987d46SWarner Losh const char * 681ca987d46SWarner Losh device_get_nameunit(device_t dev) 682ca987d46SWarner Losh { 683ca987d46SWarner Losh if (dev && dev->dev_nameunit[0]) 684ca987d46SWarner Losh return (dev->dev_nameunit); 685ca987d46SWarner Losh 686ca987d46SWarner Losh return (unknown_string); 687ca987d46SWarner Losh } 688ca987d46SWarner Losh 689ca987d46SWarner Losh static uint8_t 690ca987d46SWarner Losh devclass_create(devclass_t *dc_pp) 691ca987d46SWarner Losh { 692ca987d46SWarner Losh if (dc_pp == NULL) { 693ca987d46SWarner Losh return (1); 694ca987d46SWarner Losh } 695ca987d46SWarner Losh if (dc_pp[0] == NULL) { 696ca987d46SWarner Losh dc_pp[0] = malloc(sizeof(**(dc_pp)), 697ca987d46SWarner Losh M_DEVBUF, M_WAITOK | M_ZERO); 698ca987d46SWarner Losh 699ca987d46SWarner Losh if (dc_pp[0] == NULL) { 700ca987d46SWarner Losh return (1); 701ca987d46SWarner Losh } 702ca987d46SWarner Losh } 703ca987d46SWarner Losh return (0); 704ca987d46SWarner Losh } 705ca987d46SWarner Losh 706ca987d46SWarner Losh static const struct module_data * 707ca987d46SWarner Losh devclass_find_create(const char *classname) 708ca987d46SWarner Losh { 709ca987d46SWarner Losh const struct module_data *mod; 710ca987d46SWarner Losh 711ca987d46SWarner Losh TAILQ_FOREACH(mod, &module_head, entry) { 712ca987d46SWarner Losh if (devclass_equal(mod->mod_name, classname)) { 713ca987d46SWarner Losh if (devclass_create(mod->devclass_pp)) { 714ca987d46SWarner Losh continue; 715ca987d46SWarner Losh } 716ca987d46SWarner Losh return (mod); 717ca987d46SWarner Losh } 718ca987d46SWarner Losh } 719ca987d46SWarner Losh return (NULL); 720ca987d46SWarner Losh } 721ca987d46SWarner Losh 722ca987d46SWarner Losh static uint8_t 723ca987d46SWarner Losh devclass_add_device(const struct module_data *mod, device_t dev) 724ca987d46SWarner Losh { 725ca987d46SWarner Losh device_t *pp_dev; 726ca987d46SWarner Losh device_t *end; 727ca987d46SWarner Losh uint8_t unit; 728ca987d46SWarner Losh 729ca987d46SWarner Losh pp_dev = mod->devclass_pp[0]->dev_list; 730ca987d46SWarner Losh end = pp_dev + DEVCLASS_MAXUNIT; 731ca987d46SWarner Losh unit = 0; 732ca987d46SWarner Losh 733ca987d46SWarner Losh while (pp_dev != end) { 734ca987d46SWarner Losh if (*pp_dev == NULL) { 735ca987d46SWarner Losh *pp_dev = dev; 736ca987d46SWarner Losh dev->dev_unit = unit; 737ca987d46SWarner Losh dev->dev_module = mod; 738ca987d46SWarner Losh snprintf(dev->dev_nameunit, 739ca987d46SWarner Losh sizeof(dev->dev_nameunit), 740ca987d46SWarner Losh "%s%d", device_get_name(dev), unit); 741ca987d46SWarner Losh return (0); 742ca987d46SWarner Losh } 743ca987d46SWarner Losh pp_dev++; 744ca987d46SWarner Losh unit++; 745ca987d46SWarner Losh } 746ca987d46SWarner Losh DPRINTF("Could not add device to devclass.\n"); 747ca987d46SWarner Losh return (1); 748ca987d46SWarner Losh } 749ca987d46SWarner Losh 750ca987d46SWarner Losh static void 751ca987d46SWarner Losh devclass_delete_device(const struct module_data *mod, device_t dev) 752ca987d46SWarner Losh { 753ca987d46SWarner Losh if (mod == NULL) { 754ca987d46SWarner Losh return; 755ca987d46SWarner Losh } 756ca987d46SWarner Losh mod->devclass_pp[0]->dev_list[dev->dev_unit] = NULL; 757ca987d46SWarner Losh dev->dev_module = NULL; 758ca987d46SWarner Losh } 759ca987d46SWarner Losh 760ca987d46SWarner Losh static device_t 761ca987d46SWarner Losh make_device(device_t parent, const char *name) 762ca987d46SWarner Losh { 763ca987d46SWarner Losh device_t dev = NULL; 764ca987d46SWarner Losh const struct module_data *mod = NULL; 765ca987d46SWarner Losh 766ca987d46SWarner Losh if (name) { 767ca987d46SWarner Losh 768ca987d46SWarner Losh mod = devclass_find_create(name); 769ca987d46SWarner Losh 770ca987d46SWarner Losh if (!mod) { 771ca987d46SWarner Losh 772ca987d46SWarner Losh DPRINTF("%s:%d:%s: can't find device " 773ca987d46SWarner Losh "class %s\n", __FILE__, __LINE__, 774ca987d46SWarner Losh __FUNCTION__, name); 775ca987d46SWarner Losh 776ca987d46SWarner Losh goto done; 777ca987d46SWarner Losh } 778ca987d46SWarner Losh } 779ca987d46SWarner Losh dev = malloc(sizeof(*dev), 780ca987d46SWarner Losh M_DEVBUF, M_WAITOK | M_ZERO); 781ca987d46SWarner Losh 782ca987d46SWarner Losh if (dev == NULL) 783ca987d46SWarner Losh goto done; 784ca987d46SWarner Losh 785ca987d46SWarner Losh dev->dev_parent = parent; 786ca987d46SWarner Losh TAILQ_INIT(&dev->dev_children); 787ca987d46SWarner Losh 788ca987d46SWarner Losh if (name) { 789ca987d46SWarner Losh dev->dev_fixed_class = 1; 790ca987d46SWarner Losh if (devclass_add_device(mod, dev)) { 791ca987d46SWarner Losh goto error; 792ca987d46SWarner Losh } 793ca987d46SWarner Losh } 794ca987d46SWarner Losh done: 795ca987d46SWarner Losh return (dev); 796ca987d46SWarner Losh 797ca987d46SWarner Losh error: 798ca987d46SWarner Losh if (dev) { 799ca987d46SWarner Losh free(dev, M_DEVBUF); 800ca987d46SWarner Losh } 801ca987d46SWarner Losh return (NULL); 802ca987d46SWarner Losh } 803ca987d46SWarner Losh 804ca987d46SWarner Losh device_t 805ca987d46SWarner Losh device_add_child(device_t dev, const char *name, int unit) 806ca987d46SWarner Losh { 807ca987d46SWarner Losh device_t child; 808ca987d46SWarner Losh 809ca987d46SWarner Losh if (unit != -1) { 810ca987d46SWarner Losh device_printf(dev, "Unit is not -1\n"); 811ca987d46SWarner Losh } 812ca987d46SWarner Losh child = make_device(dev, name); 813ca987d46SWarner Losh if (child == NULL) { 814ca987d46SWarner Losh device_printf(dev, "Could not add child '%s'\n", name); 815ca987d46SWarner Losh goto done; 816ca987d46SWarner Losh } 817ca987d46SWarner Losh if (dev == NULL) { 818ca987d46SWarner Losh /* no parent */ 819ca987d46SWarner Losh goto done; 820ca987d46SWarner Losh } 821ca987d46SWarner Losh TAILQ_INSERT_TAIL(&dev->dev_children, child, dev_link); 822ca987d46SWarner Losh done: 823ca987d46SWarner Losh return (child); 824ca987d46SWarner Losh } 825ca987d46SWarner Losh 826ca987d46SWarner Losh int 827ca987d46SWarner Losh device_delete_child(device_t dev, device_t child) 828ca987d46SWarner Losh { 829ca987d46SWarner Losh int error = 0; 830ca987d46SWarner Losh device_t grandchild; 831ca987d46SWarner Losh 832ca987d46SWarner Losh /* detach parent before deleting children, if any */ 833ca987d46SWarner Losh error = device_detach(child); 834ca987d46SWarner Losh if (error) 835ca987d46SWarner Losh goto done; 836ca987d46SWarner Losh 837ca987d46SWarner Losh /* remove children second */ 838ca987d46SWarner Losh while ((grandchild = TAILQ_FIRST(&child->dev_children))) { 839ca987d46SWarner Losh error = device_delete_child(child, grandchild); 840ca987d46SWarner Losh if (error) { 841ca987d46SWarner Losh device_printf(dev, "Error deleting child!\n"); 842ca987d46SWarner Losh goto done; 843ca987d46SWarner Losh } 844ca987d46SWarner Losh } 845ca987d46SWarner Losh 846ca987d46SWarner Losh devclass_delete_device(child->dev_module, child); 847ca987d46SWarner Losh 848ca987d46SWarner Losh if (dev != NULL) { 849ca987d46SWarner Losh /* remove child from parent */ 850ca987d46SWarner Losh TAILQ_REMOVE(&dev->dev_children, child, dev_link); 851ca987d46SWarner Losh } 852ca987d46SWarner Losh free(child, M_DEVBUF); 853ca987d46SWarner Losh 854ca987d46SWarner Losh done: 855ca987d46SWarner Losh return (error); 856ca987d46SWarner Losh } 857ca987d46SWarner Losh 858ca987d46SWarner Losh int 859ca987d46SWarner Losh device_delete_children(device_t dev) 860ca987d46SWarner Losh { 861ca987d46SWarner Losh device_t child; 862ca987d46SWarner Losh int error = 0; 863ca987d46SWarner Losh 864ca987d46SWarner Losh while ((child = TAILQ_FIRST(&dev->dev_children))) { 865ca987d46SWarner Losh error = device_delete_child(dev, child); 866ca987d46SWarner Losh if (error) { 867ca987d46SWarner Losh device_printf(dev, "Error deleting child!\n"); 868ca987d46SWarner Losh break; 869ca987d46SWarner Losh } 870ca987d46SWarner Losh } 871ca987d46SWarner Losh return (error); 872ca987d46SWarner Losh } 873ca987d46SWarner Losh 874ca987d46SWarner Losh void 875ca987d46SWarner Losh device_quiet(device_t dev) 876ca987d46SWarner Losh { 877ca987d46SWarner Losh dev->dev_quiet = 1; 878ca987d46SWarner Losh } 879ca987d46SWarner Losh 880ca987d46SWarner Losh const char * 881ca987d46SWarner Losh device_get_desc(device_t dev) 882ca987d46SWarner Losh { 883ca987d46SWarner Losh if (dev) 884ca987d46SWarner Losh return &(dev->dev_desc[0]); 885ca987d46SWarner Losh return (unknown_string); 886ca987d46SWarner Losh } 887ca987d46SWarner Losh 888ca987d46SWarner Losh static int 889ca987d46SWarner Losh default_method(void) 890ca987d46SWarner Losh { 891ca987d46SWarner Losh /* do nothing */ 892ca987d46SWarner Losh DPRINTF("Default method called\n"); 893ca987d46SWarner Losh return (0); 894ca987d46SWarner Losh } 895ca987d46SWarner Losh 896ca987d46SWarner Losh void * 897ca987d46SWarner Losh device_get_method(device_t dev, const char *what) 898ca987d46SWarner Losh { 899ca987d46SWarner Losh const struct device_method *mtod; 900ca987d46SWarner Losh 901ca987d46SWarner Losh mtod = dev->dev_module->driver->methods; 902ca987d46SWarner Losh while (mtod->func != NULL) { 903ca987d46SWarner Losh if (devclass_equal(mtod->desc, what)) { 904ca987d46SWarner Losh return (mtod->func); 905ca987d46SWarner Losh } 906ca987d46SWarner Losh mtod++; 907ca987d46SWarner Losh } 908ca987d46SWarner Losh return ((void *)&default_method); 909ca987d46SWarner Losh } 910ca987d46SWarner Losh 911ca987d46SWarner Losh const char * 912ca987d46SWarner Losh device_get_name(device_t dev) 913ca987d46SWarner Losh { 914ca987d46SWarner Losh if (dev == NULL) 915ca987d46SWarner Losh return (unknown_string); 916ca987d46SWarner Losh 917ca987d46SWarner Losh return (dev->dev_module->driver->name); 918ca987d46SWarner Losh } 919ca987d46SWarner Losh 920ca987d46SWarner Losh static int 921ca987d46SWarner Losh device_allocate_softc(device_t dev) 922ca987d46SWarner Losh { 923ca987d46SWarner Losh const struct module_data *mod; 924ca987d46SWarner Losh 925ca987d46SWarner Losh mod = dev->dev_module; 926ca987d46SWarner Losh 927ca987d46SWarner Losh if ((dev->dev_softc_alloc == 0) && 928ca987d46SWarner Losh (mod->driver->size != 0)) { 929ca987d46SWarner Losh dev->dev_sc = malloc(mod->driver->size, 930ca987d46SWarner Losh M_DEVBUF, M_WAITOK | M_ZERO); 931ca987d46SWarner Losh 932ca987d46SWarner Losh if (dev->dev_sc == NULL) 933ca987d46SWarner Losh return (ENOMEM); 934ca987d46SWarner Losh 935ca987d46SWarner Losh dev->dev_softc_alloc = 1; 936ca987d46SWarner Losh } 937ca987d46SWarner Losh return (0); 938ca987d46SWarner Losh } 939ca987d46SWarner Losh 940ca987d46SWarner Losh int 941ca987d46SWarner Losh device_probe_and_attach(device_t dev) 942ca987d46SWarner Losh { 943ca987d46SWarner Losh const struct module_data *mod; 944ca987d46SWarner Losh const char *bus_name_parent; 945ca987d46SWarner Losh 946ca987d46SWarner Losh bus_name_parent = device_get_name(device_get_parent(dev)); 947ca987d46SWarner Losh 948ca987d46SWarner Losh if (dev->dev_attached) 949ca987d46SWarner Losh return (0); /* fail-safe */ 950ca987d46SWarner Losh 951ca987d46SWarner Losh if (dev->dev_fixed_class) { 952ca987d46SWarner Losh 953ca987d46SWarner Losh mod = dev->dev_module; 954ca987d46SWarner Losh 955ca987d46SWarner Losh if (DEVICE_PROBE(dev) <= 0) { 956ca987d46SWarner Losh 957ca987d46SWarner Losh if (device_allocate_softc(dev) == 0) { 958ca987d46SWarner Losh 959ca987d46SWarner Losh if (DEVICE_ATTACH(dev) == 0) { 960ca987d46SWarner Losh /* success */ 961ca987d46SWarner Losh dev->dev_attached = 1; 962ca987d46SWarner Losh return (0); 963ca987d46SWarner Losh } 964ca987d46SWarner Losh } 965ca987d46SWarner Losh } 966ca987d46SWarner Losh device_detach(dev); 967ca987d46SWarner Losh 968ca987d46SWarner Losh goto error; 969ca987d46SWarner Losh } 970ca987d46SWarner Losh /* 971ca987d46SWarner Losh * Else find a module for our device, if any 972ca987d46SWarner Losh */ 973ca987d46SWarner Losh 974ca987d46SWarner Losh TAILQ_FOREACH(mod, &module_head, entry) { 975ca987d46SWarner Losh if (devclass_equal(mod->bus_name, bus_name_parent)) { 976ca987d46SWarner Losh if (devclass_create(mod->devclass_pp)) { 977ca987d46SWarner Losh continue; 978ca987d46SWarner Losh } 979ca987d46SWarner Losh if (devclass_add_device(mod, dev)) { 980ca987d46SWarner Losh continue; 981ca987d46SWarner Losh } 982ca987d46SWarner Losh if (DEVICE_PROBE(dev) <= 0) { 983ca987d46SWarner Losh 984ca987d46SWarner Losh if (device_allocate_softc(dev) == 0) { 985ca987d46SWarner Losh 986ca987d46SWarner Losh if (DEVICE_ATTACH(dev) == 0) { 987ca987d46SWarner Losh /* success */ 988ca987d46SWarner Losh dev->dev_attached = 1; 989ca987d46SWarner Losh return (0); 990ca987d46SWarner Losh } 991ca987d46SWarner Losh } 992ca987d46SWarner Losh } 993ca987d46SWarner Losh /* else try next driver */ 994ca987d46SWarner Losh 995ca987d46SWarner Losh device_detach(dev); 996ca987d46SWarner Losh } 997ca987d46SWarner Losh } 998ca987d46SWarner Losh 999ca987d46SWarner Losh error: 1000ca987d46SWarner Losh return (ENODEV); 1001ca987d46SWarner Losh } 1002ca987d46SWarner Losh 1003ca987d46SWarner Losh int 1004ca987d46SWarner Losh device_detach(device_t dev) 1005ca987d46SWarner Losh { 1006ca987d46SWarner Losh const struct module_data *mod = dev->dev_module; 1007ca987d46SWarner Losh int error; 1008ca987d46SWarner Losh 1009ca987d46SWarner Losh if (dev->dev_attached) { 1010ca987d46SWarner Losh 1011ca987d46SWarner Losh error = DEVICE_DETACH(dev); 1012ca987d46SWarner Losh if (error) { 1013ca987d46SWarner Losh return error; 1014ca987d46SWarner Losh } 1015ca987d46SWarner Losh dev->dev_attached = 0; 1016ca987d46SWarner Losh } 1017ca987d46SWarner Losh device_set_softc(dev, NULL); 1018ca987d46SWarner Losh 1019ca987d46SWarner Losh if (dev->dev_fixed_class == 0) 1020ca987d46SWarner Losh devclass_delete_device(mod, dev); 1021ca987d46SWarner Losh 1022ca987d46SWarner Losh return (0); 1023ca987d46SWarner Losh } 1024ca987d46SWarner Losh 1025ca987d46SWarner Losh void 1026ca987d46SWarner Losh device_set_softc(device_t dev, void *softc) 1027ca987d46SWarner Losh { 1028ca987d46SWarner Losh if (dev->dev_softc_alloc) { 1029ca987d46SWarner Losh free(dev->dev_sc, M_DEVBUF); 1030ca987d46SWarner Losh dev->dev_sc = NULL; 1031ca987d46SWarner Losh } 1032ca987d46SWarner Losh dev->dev_sc = softc; 1033ca987d46SWarner Losh dev->dev_softc_alloc = 0; 1034ca987d46SWarner Losh } 1035ca987d46SWarner Losh 1036ca987d46SWarner Losh void * 1037ca987d46SWarner Losh device_get_softc(device_t dev) 1038ca987d46SWarner Losh { 1039ca987d46SWarner Losh if (dev == NULL) 1040ca987d46SWarner Losh return (NULL); 1041ca987d46SWarner Losh 1042ca987d46SWarner Losh return (dev->dev_sc); 1043ca987d46SWarner Losh } 1044ca987d46SWarner Losh 1045ca987d46SWarner Losh int 1046ca987d46SWarner Losh device_is_attached(device_t dev) 1047ca987d46SWarner Losh { 1048ca987d46SWarner Losh return (dev->dev_attached); 1049ca987d46SWarner Losh } 1050ca987d46SWarner Losh 1051ca987d46SWarner Losh void 1052ca987d46SWarner Losh device_set_desc(device_t dev, const char *desc) 1053ca987d46SWarner Losh { 1054ca987d46SWarner Losh snprintf(dev->dev_desc, sizeof(dev->dev_desc), "%s", desc); 1055ca987d46SWarner Losh } 1056ca987d46SWarner Losh 1057ca987d46SWarner Losh void 1058ca987d46SWarner Losh device_set_desc_copy(device_t dev, const char *desc) 1059ca987d46SWarner Losh { 1060ca987d46SWarner Losh device_set_desc(dev, desc); 1061ca987d46SWarner Losh } 1062ca987d46SWarner Losh 1063ca987d46SWarner Losh void * 1064ca987d46SWarner Losh devclass_get_softc(devclass_t dc, int unit) 1065ca987d46SWarner Losh { 1066ca987d46SWarner Losh return (device_get_softc(devclass_get_device(dc, unit))); 1067ca987d46SWarner Losh } 1068ca987d46SWarner Losh 1069ca987d46SWarner Losh int 1070ca987d46SWarner Losh devclass_get_maxunit(devclass_t dc) 1071ca987d46SWarner Losh { 1072ca987d46SWarner Losh int max_unit = 0; 1073ca987d46SWarner Losh 1074ca987d46SWarner Losh if (dc) { 1075ca987d46SWarner Losh max_unit = DEVCLASS_MAXUNIT; 1076ca987d46SWarner Losh while (max_unit--) { 1077ca987d46SWarner Losh if (dc->dev_list[max_unit]) { 1078ca987d46SWarner Losh break; 1079ca987d46SWarner Losh } 1080ca987d46SWarner Losh } 1081ca987d46SWarner Losh max_unit++; 1082ca987d46SWarner Losh } 1083ca987d46SWarner Losh return (max_unit); 1084ca987d46SWarner Losh } 1085ca987d46SWarner Losh 1086ca987d46SWarner Losh device_t 1087ca987d46SWarner Losh devclass_get_device(devclass_t dc, int unit) 1088ca987d46SWarner Losh { 1089ca987d46SWarner Losh return (((unit < 0) || (unit >= DEVCLASS_MAXUNIT) || (dc == NULL)) ? 1090ca987d46SWarner Losh NULL : dc->dev_list[unit]); 1091ca987d46SWarner Losh } 1092ca987d46SWarner Losh 1093ca987d46SWarner Losh devclass_t 1094ca987d46SWarner Losh devclass_find(const char *classname) 1095ca987d46SWarner Losh { 1096ca987d46SWarner Losh const struct module_data *mod; 1097ca987d46SWarner Losh 1098ca987d46SWarner Losh TAILQ_FOREACH(mod, &module_head, entry) { 1099ca987d46SWarner Losh if (devclass_equal(mod->driver->name, classname)) 1100ca987d46SWarner Losh return (mod->devclass_pp[0]); 1101ca987d46SWarner Losh } 1102ca987d46SWarner Losh return (NULL); 1103ca987d46SWarner Losh } 1104ca987d46SWarner Losh 1105ca987d46SWarner Losh void 1106ca987d46SWarner Losh module_register(void *data) 1107ca987d46SWarner Losh { 1108ca987d46SWarner Losh struct module_data *mdata = data; 1109ca987d46SWarner Losh 1110ca987d46SWarner Losh TAILQ_INSERT_TAIL(&module_head, mdata, entry); 1111ca987d46SWarner Losh } 1112ca987d46SWarner Losh 1113ca987d46SWarner Losh /*------------------------------------------------------------------------* 1114ca987d46SWarner Losh * System startup 1115ca987d46SWarner Losh *------------------------------------------------------------------------*/ 1116ca987d46SWarner Losh 1117ca987d46SWarner Losh static void 1118ca987d46SWarner Losh sysinit_run(const void **ppdata) 1119ca987d46SWarner Losh { 1120ca987d46SWarner Losh const struct sysinit *psys; 1121ca987d46SWarner Losh 1122ca987d46SWarner Losh while ((psys = *ppdata) != NULL) { 1123ca987d46SWarner Losh (psys->func) (psys->data); 1124ca987d46SWarner Losh ppdata++; 1125ca987d46SWarner Losh } 1126ca987d46SWarner Losh } 1127ca987d46SWarner Losh 1128ca987d46SWarner Losh /*------------------------------------------------------------------------* 1129ca987d46SWarner Losh * USB process API 1130ca987d46SWarner Losh *------------------------------------------------------------------------*/ 1131ca987d46SWarner Losh 1132ca987d46SWarner Losh static int usb_do_process(struct usb_process *); 1133ca987d46SWarner Losh static int usb_proc_level = -1; 1134ca987d46SWarner Losh static struct mtx usb_proc_mtx; 1135ca987d46SWarner Losh 1136ca987d46SWarner Losh void 1137ca987d46SWarner Losh usb_idle(void) 1138ca987d46SWarner Losh { 1139ca987d46SWarner Losh int old_level = usb_proc_level; 1140ca987d46SWarner Losh int old_giant = Giant.owned; 1141ca987d46SWarner Losh int worked; 1142ca987d46SWarner Losh 1143ca987d46SWarner Losh device_run_interrupts(usb_pci_root); 1144ca987d46SWarner Losh 1145ca987d46SWarner Losh do { 1146ca987d46SWarner Losh worked = 0; 1147ca987d46SWarner Losh Giant.owned = 0; 1148ca987d46SWarner Losh 1149ca987d46SWarner Losh while (++usb_proc_level < USB_PROC_MAX) 1150ca987d46SWarner Losh worked |= usb_do_process(usb_process + usb_proc_level); 1151ca987d46SWarner Losh 1152ca987d46SWarner Losh usb_proc_level = old_level; 1153ca987d46SWarner Losh Giant.owned = old_giant; 1154ca987d46SWarner Losh 1155ca987d46SWarner Losh } while (worked); 1156ca987d46SWarner Losh } 1157ca987d46SWarner Losh 1158ca987d46SWarner Losh void 1159ca987d46SWarner Losh usb_init(void) 1160ca987d46SWarner Losh { 1161ca987d46SWarner Losh sysinit_run(sysinit_data); 1162ca987d46SWarner Losh } 1163ca987d46SWarner Losh 1164ca987d46SWarner Losh void 1165ca987d46SWarner Losh usb_uninit(void) 1166ca987d46SWarner Losh { 1167ca987d46SWarner Losh sysinit_run(sysuninit_data); 1168ca987d46SWarner Losh } 1169ca987d46SWarner Losh 1170ca987d46SWarner Losh static void 1171ca987d46SWarner Losh usb_process_init_sub(struct usb_process *up) 1172ca987d46SWarner Losh { 1173ca987d46SWarner Losh TAILQ_INIT(&up->up_qhead); 1174ca987d46SWarner Losh 1175ca987d46SWarner Losh cv_init(&up->up_cv, "-"); 1176ca987d46SWarner Losh cv_init(&up->up_drain, "usbdrain"); 1177ca987d46SWarner Losh 1178ca987d46SWarner Losh up->up_mtx = &usb_proc_mtx; 1179ca987d46SWarner Losh } 1180ca987d46SWarner Losh 1181ca987d46SWarner Losh static void 1182ca987d46SWarner Losh usb_process_init(void *arg) 1183ca987d46SWarner Losh { 1184ca987d46SWarner Losh uint8_t x; 1185ca987d46SWarner Losh 1186ca987d46SWarner Losh mtx_init(&usb_proc_mtx, "usb-proc-mtx", NULL, MTX_DEF | MTX_RECURSE); 1187ca987d46SWarner Losh 1188ca987d46SWarner Losh for (x = 0; x != USB_PROC_MAX; x++) 1189ca987d46SWarner Losh usb_process_init_sub(&usb_process[x]); 1190ca987d46SWarner Losh 1191ca987d46SWarner Losh } 1192ca987d46SWarner Losh SYSINIT(usb_process_init, SI_SUB_LOCK, SI_ORDER_MIDDLE, usb_process_init, NULL); 1193ca987d46SWarner Losh 1194ca987d46SWarner Losh static int 1195ca987d46SWarner Losh usb_do_process(struct usb_process *up) 1196ca987d46SWarner Losh { 1197ca987d46SWarner Losh struct usb_proc_msg *pm; 1198ca987d46SWarner Losh int worked = 0; 1199ca987d46SWarner Losh 1200ca987d46SWarner Losh mtx_lock(&usb_proc_mtx); 1201ca987d46SWarner Losh 1202ca987d46SWarner Losh repeat: 1203ca987d46SWarner Losh pm = TAILQ_FIRST(&up->up_qhead); 1204ca987d46SWarner Losh 1205ca987d46SWarner Losh if (pm != NULL) { 1206ca987d46SWarner Losh 1207ca987d46SWarner Losh worked = 1; 1208ca987d46SWarner Losh 1209ca987d46SWarner Losh (pm->pm_callback) (pm); 1210ca987d46SWarner Losh 1211ca987d46SWarner Losh if (pm == TAILQ_FIRST(&up->up_qhead)) { 1212ca987d46SWarner Losh /* nothing changed */ 1213ca987d46SWarner Losh TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); 1214ca987d46SWarner Losh pm->pm_qentry.tqe_prev = NULL; 1215ca987d46SWarner Losh } 1216ca987d46SWarner Losh goto repeat; 1217ca987d46SWarner Losh } 1218ca987d46SWarner Losh mtx_unlock(&usb_proc_mtx); 1219ca987d46SWarner Losh 1220ca987d46SWarner Losh return (worked); 1221ca987d46SWarner Losh } 1222ca987d46SWarner Losh 1223ca987d46SWarner Losh void * 1224ca987d46SWarner Losh usb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1) 1225ca987d46SWarner Losh { 1226ca987d46SWarner Losh struct usb_proc_msg *pm0 = _pm0; 1227ca987d46SWarner Losh struct usb_proc_msg *pm1 = _pm1; 1228ca987d46SWarner Losh struct usb_proc_msg *pm2; 1229ca987d46SWarner Losh usb_size_t d; 1230ca987d46SWarner Losh uint8_t t; 1231ca987d46SWarner Losh 1232ca987d46SWarner Losh t = 0; 1233ca987d46SWarner Losh 1234ca987d46SWarner Losh if (pm0->pm_qentry.tqe_prev) { 1235ca987d46SWarner Losh t |= 1; 1236ca987d46SWarner Losh } 1237ca987d46SWarner Losh if (pm1->pm_qentry.tqe_prev) { 1238ca987d46SWarner Losh t |= 2; 1239ca987d46SWarner Losh } 1240ca987d46SWarner Losh if (t == 0) { 1241ca987d46SWarner Losh /* 1242ca987d46SWarner Losh * No entries are queued. Queue "pm0" and use the existing 1243ca987d46SWarner Losh * message number. 1244ca987d46SWarner Losh */ 1245ca987d46SWarner Losh pm2 = pm0; 1246ca987d46SWarner Losh } else if (t == 1) { 1247ca987d46SWarner Losh /* Check if we need to increment the message number. */ 1248ca987d46SWarner Losh if (pm0->pm_num == up->up_msg_num) { 1249ca987d46SWarner Losh up->up_msg_num++; 1250ca987d46SWarner Losh } 1251ca987d46SWarner Losh pm2 = pm1; 1252ca987d46SWarner Losh } else if (t == 2) { 1253ca987d46SWarner Losh /* Check if we need to increment the message number. */ 1254ca987d46SWarner Losh if (pm1->pm_num == up->up_msg_num) { 1255ca987d46SWarner Losh up->up_msg_num++; 1256ca987d46SWarner Losh } 1257ca987d46SWarner Losh pm2 = pm0; 1258ca987d46SWarner Losh } else if (t == 3) { 1259ca987d46SWarner Losh /* 1260ca987d46SWarner Losh * Both entries are queued. Re-queue the entry closest to 1261ca987d46SWarner Losh * the end. 1262ca987d46SWarner Losh */ 1263ca987d46SWarner Losh d = (pm1->pm_num - pm0->pm_num); 1264ca987d46SWarner Losh 1265ca987d46SWarner Losh /* Check sign after subtraction */ 1266ca987d46SWarner Losh if (d & 0x80000000) { 1267ca987d46SWarner Losh pm2 = pm0; 1268ca987d46SWarner Losh } else { 1269ca987d46SWarner Losh pm2 = pm1; 1270ca987d46SWarner Losh } 1271ca987d46SWarner Losh 1272ca987d46SWarner Losh TAILQ_REMOVE(&up->up_qhead, pm2, pm_qentry); 1273ca987d46SWarner Losh } else { 1274ca987d46SWarner Losh pm2 = NULL; /* panic - should not happen */ 1275ca987d46SWarner Losh } 1276ca987d46SWarner Losh 1277ca987d46SWarner Losh /* Put message last on queue */ 1278ca987d46SWarner Losh 1279ca987d46SWarner Losh pm2->pm_num = up->up_msg_num; 1280ca987d46SWarner Losh TAILQ_INSERT_TAIL(&up->up_qhead, pm2, pm_qentry); 1281ca987d46SWarner Losh 1282ca987d46SWarner Losh return (pm2); 1283ca987d46SWarner Losh } 1284ca987d46SWarner Losh 1285ca987d46SWarner Losh /*------------------------------------------------------------------------* 1286ca987d46SWarner Losh * usb_proc_is_gone 1287ca987d46SWarner Losh * 1288ca987d46SWarner Losh * Return values: 1289ca987d46SWarner Losh * 0: USB process is running 1290ca987d46SWarner Losh * Else: USB process is tearing down 1291ca987d46SWarner Losh *------------------------------------------------------------------------*/ 1292ca987d46SWarner Losh uint8_t 1293ca987d46SWarner Losh usb_proc_is_gone(struct usb_process *up) 1294ca987d46SWarner Losh { 1295ca987d46SWarner Losh return (0); 1296ca987d46SWarner Losh } 1297ca987d46SWarner Losh 1298ca987d46SWarner Losh /*------------------------------------------------------------------------* 1299ca987d46SWarner Losh * usb_proc_mwait 1300ca987d46SWarner Losh * 1301ca987d46SWarner Losh * This function will return when the USB process message pointed to 1302ca987d46SWarner Losh * by "pm" is no longer on a queue. This function must be called 1303ca987d46SWarner Losh * having "usb_proc_mtx" locked. 1304ca987d46SWarner Losh *------------------------------------------------------------------------*/ 1305ca987d46SWarner Losh void 1306ca987d46SWarner Losh usb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1) 1307ca987d46SWarner Losh { 1308ca987d46SWarner Losh struct usb_proc_msg *pm0 = _pm0; 1309ca987d46SWarner Losh struct usb_proc_msg *pm1 = _pm1; 1310ca987d46SWarner Losh 1311ca987d46SWarner Losh /* Just remove the messages from the queue. */ 1312ca987d46SWarner Losh if (pm0->pm_qentry.tqe_prev) { 1313ca987d46SWarner Losh TAILQ_REMOVE(&up->up_qhead, pm0, pm_qentry); 1314ca987d46SWarner Losh pm0->pm_qentry.tqe_prev = NULL; 1315ca987d46SWarner Losh } 1316ca987d46SWarner Losh if (pm1->pm_qentry.tqe_prev) { 1317ca987d46SWarner Losh TAILQ_REMOVE(&up->up_qhead, pm1, pm_qentry); 1318ca987d46SWarner Losh pm1->pm_qentry.tqe_prev = NULL; 1319ca987d46SWarner Losh } 1320ca987d46SWarner Losh } 1321ca987d46SWarner Losh 1322ca987d46SWarner Losh /*------------------------------------------------------------------------* 1323ca987d46SWarner Losh * SYSTEM attach 1324ca987d46SWarner Losh *------------------------------------------------------------------------*/ 1325ca987d46SWarner Losh 1326ca987d46SWarner Losh #ifdef USB_PCI_PROBE_LIST 1327ca987d46SWarner Losh static device_method_t pci_methods[] = { 1328ca987d46SWarner Losh DEVMETHOD_END 1329ca987d46SWarner Losh }; 1330ca987d46SWarner Losh 1331ca987d46SWarner Losh static driver_t pci_driver = { 1332ca987d46SWarner Losh .name = "pci", 1333ca987d46SWarner Losh .methods = pci_methods, 1334ca987d46SWarner Losh }; 1335ca987d46SWarner Losh 1336ca987d46SWarner Losh static devclass_t pci_devclass; 1337ca987d46SWarner Losh 1338ca987d46SWarner Losh DRIVER_MODULE(pci, pci, pci_driver, pci_devclass, 0, 0); 1339ca987d46SWarner Losh 1340ca987d46SWarner Losh static const char *usb_pci_devices[] = { 1341ca987d46SWarner Losh USB_PCI_PROBE_LIST 1342ca987d46SWarner Losh }; 1343ca987d46SWarner Losh 1344ca987d46SWarner Losh #define USB_PCI_USB_MAX (sizeof(usb_pci_devices) / sizeof(void *)) 1345ca987d46SWarner Losh 1346ca987d46SWarner Losh static device_t usb_pci_dev[USB_PCI_USB_MAX]; 1347ca987d46SWarner Losh 1348ca987d46SWarner Losh static void 1349ca987d46SWarner Losh usb_pci_mod_load(void *arg) 1350ca987d46SWarner Losh { 1351ca987d46SWarner Losh uint32_t x; 1352ca987d46SWarner Losh 1353ca987d46SWarner Losh usb_pci_root = device_add_child(NULL, "pci", -1); 1354ca987d46SWarner Losh if (usb_pci_root == NULL) 1355ca987d46SWarner Losh return; 1356ca987d46SWarner Losh 1357ca987d46SWarner Losh for (x = 0; x != USB_PCI_USB_MAX; x++) { 1358ca987d46SWarner Losh usb_pci_dev[x] = device_add_child(usb_pci_root, usb_pci_devices[x], -1); 1359ca987d46SWarner Losh if (usb_pci_dev[x] == NULL) 1360ca987d46SWarner Losh continue; 1361ca987d46SWarner Losh if (device_probe_and_attach(usb_pci_dev[x])) { 1362ca987d46SWarner Losh device_printf(usb_pci_dev[x], 1363ca987d46SWarner Losh "WARNING: Probe and attach failed!\n"); 1364ca987d46SWarner Losh } 1365ca987d46SWarner Losh } 1366ca987d46SWarner Losh } 1367ca987d46SWarner Losh SYSINIT(usb_pci_mod_load, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_load, 0); 1368ca987d46SWarner Losh 1369ca987d46SWarner Losh static void 1370ca987d46SWarner Losh usb_pci_mod_unload(void *arg) 1371ca987d46SWarner Losh { 1372ca987d46SWarner Losh uint32_t x; 1373ca987d46SWarner Losh 1374ca987d46SWarner Losh for (x = 0; x != USB_PCI_USB_MAX; x++) { 1375ca987d46SWarner Losh if (usb_pci_dev[x]) { 1376ca987d46SWarner Losh device_detach(usb_pci_dev[x]); 1377ca987d46SWarner Losh device_delete_child(usb_pci_root, usb_pci_dev[x]); 1378ca987d46SWarner Losh } 1379ca987d46SWarner Losh } 1380ca987d46SWarner Losh if (usb_pci_root) 1381ca987d46SWarner Losh device_delete_child(NULL, usb_pci_root); 1382ca987d46SWarner Losh } 1383ca987d46SWarner Losh SYSUNINIT(usb_pci_mod_unload, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, usb_pci_mod_unload, 0); 1384ca987d46SWarner Losh #endif 1385ca987d46SWarner Losh 1386ca987d46SWarner Losh /*------------------------------------------------------------------------* 1387ca987d46SWarner Losh * MALLOC API 1388ca987d46SWarner Losh *------------------------------------------------------------------------*/ 1389ca987d46SWarner Losh 1390ca987d46SWarner Losh #ifndef HAVE_MALLOC 1391ca987d46SWarner Losh #define USB_POOL_ALIGN 8 1392ca987d46SWarner Losh 1393ca987d46SWarner Losh static uint8_t usb_pool[USB_POOL_SIZE] __aligned(USB_POOL_ALIGN); 1394ca987d46SWarner Losh static uint32_t usb_pool_rem = USB_POOL_SIZE; 1395ca987d46SWarner Losh static uint32_t usb_pool_entries; 1396ca987d46SWarner Losh 1397ca987d46SWarner Losh struct malloc_hdr { 1398ca987d46SWarner Losh TAILQ_ENTRY(malloc_hdr) entry; 1399ca987d46SWarner Losh uint32_t size; 1400ca987d46SWarner Losh } __aligned(USB_POOL_ALIGN); 1401ca987d46SWarner Losh 1402ca987d46SWarner Losh static TAILQ_HEAD(, malloc_hdr) malloc_head = 1403ca987d46SWarner Losh TAILQ_HEAD_INITIALIZER(malloc_head); 1404ca987d46SWarner Losh 1405ca987d46SWarner Losh void * 1406ca987d46SWarner Losh usb_malloc(unsigned long size) 1407ca987d46SWarner Losh { 1408ca987d46SWarner Losh struct malloc_hdr *hdr; 1409ca987d46SWarner Losh 1410ca987d46SWarner Losh size = (size + USB_POOL_ALIGN - 1) & ~(USB_POOL_ALIGN - 1); 1411ca987d46SWarner Losh size += sizeof(struct malloc_hdr); 1412ca987d46SWarner Losh 1413ca987d46SWarner Losh TAILQ_FOREACH(hdr, &malloc_head, entry) { 1414ca987d46SWarner Losh if (hdr->size == size) 1415ca987d46SWarner Losh break; 1416ca987d46SWarner Losh } 1417ca987d46SWarner Losh 1418ca987d46SWarner Losh if (hdr) { 1419ca987d46SWarner Losh DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1420ca987d46SWarner Losh (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1421ca987d46SWarner Losh 1422ca987d46SWarner Losh TAILQ_REMOVE(&malloc_head, hdr, entry); 1423ca987d46SWarner Losh memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1424ca987d46SWarner Losh return (hdr + 1); 1425ca987d46SWarner Losh } 1426ca987d46SWarner Losh if (usb_pool_rem >= size) { 1427ca987d46SWarner Losh hdr = (void *)(usb_pool + USB_POOL_SIZE - usb_pool_rem); 1428ca987d46SWarner Losh hdr->size = size; 1429ca987d46SWarner Losh 1430ca987d46SWarner Losh usb_pool_rem -= size; 1431ca987d46SWarner Losh usb_pool_entries++; 1432ca987d46SWarner Losh 1433ca987d46SWarner Losh DPRINTF("MALLOC: Entries = %d; Remainder = %d; Size = %d\n", 1434ca987d46SWarner Losh (int)usb_pool_entries, (int)usb_pool_rem, (int)size); 1435ca987d46SWarner Losh 1436ca987d46SWarner Losh memset(hdr + 1, 0, hdr->size - sizeof(*hdr)); 1437ca987d46SWarner Losh return (hdr + 1); 1438ca987d46SWarner Losh } 1439ca987d46SWarner Losh return (NULL); 1440ca987d46SWarner Losh } 1441ca987d46SWarner Losh 1442ca987d46SWarner Losh void 1443ca987d46SWarner Losh usb_free(void *arg) 1444ca987d46SWarner Losh { 1445ca987d46SWarner Losh struct malloc_hdr *hdr; 1446ca987d46SWarner Losh 1447ca987d46SWarner Losh if (arg == NULL) 1448ca987d46SWarner Losh return; 1449ca987d46SWarner Losh 1450ca987d46SWarner Losh hdr = arg; 1451ca987d46SWarner Losh hdr--; 1452ca987d46SWarner Losh 1453ca987d46SWarner Losh TAILQ_INSERT_TAIL(&malloc_head, hdr, entry); 1454ca987d46SWarner Losh } 1455ca987d46SWarner Losh #endif 1456ca987d46SWarner Losh 1457ca987d46SWarner Losh char * 1458ca987d46SWarner Losh usb_strdup(const char *str) 1459ca987d46SWarner Losh { 1460ca987d46SWarner Losh char *tmp; 1461ca987d46SWarner Losh int len; 1462ca987d46SWarner Losh 1463ca987d46SWarner Losh len = 1 + strlen(str); 1464ca987d46SWarner Losh 1465ca987d46SWarner Losh tmp = malloc(len,XXX,XXX); 1466ca987d46SWarner Losh if (tmp == NULL) 1467ca987d46SWarner Losh return (NULL); 1468ca987d46SWarner Losh 1469ca987d46SWarner Losh memcpy(tmp, str, len); 1470ca987d46SWarner Losh return (tmp); 1471ca987d46SWarner Losh } 1472