bas-gigaset.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,371 行 · 第 1/5 页
C
2,371 行
/* kill URBs and tasklets before freeing - better safe than sorry */ atomic_set(&ubc->running, 0); for (i = 0; i < BAS_OUTURBS; ++i) if (ubc->isoouturbs[i].urb) { gig_dbg(DEBUG_INIT, "%s: killing iso out URB %d", __func__, i); usb_kill_urb(ubc->isoouturbs[i].urb); usb_free_urb(ubc->isoouturbs[i].urb); } for (i = 0; i < BAS_INURBS; ++i) if (ubc->isoinurbs[i]) { gig_dbg(DEBUG_INIT, "%s: killing iso in URB %d", __func__, i); usb_kill_urb(ubc->isoinurbs[i]); usb_free_urb(ubc->isoinurbs[i]); } tasklet_kill(&ubc->sent_tasklet); tasklet_kill(&ubc->rcvd_tasklet); kfree(ubc->isooutbuf); kfree(ubc); bcs->hw.bas = NULL; return 1;}/* Initialize hardware dependent part of the B channel structure * parameter: * bcs B channel structure * return value: * !=0 on success */static int gigaset_initbcshw(struct bc_state *bcs){ int i; struct bas_bc_state *ubc; bcs->hw.bas = ubc = kmalloc(sizeof(struct bas_bc_state), GFP_KERNEL); if (!ubc) { err("could not allocate bas_bc_state"); return 0; } atomic_set(&ubc->running, 0); atomic_set(&ubc->corrbytes, 0); spin_lock_init(&ubc->isooutlock); for (i = 0; i < BAS_OUTURBS; ++i) { ubc->isoouturbs[i].urb = NULL; ubc->isoouturbs[i].bcs = bcs; } ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL; ubc->numsub = 0; if (!(ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL))) { err("could not allocate isochronous output buffer"); kfree(ubc); bcs->hw.bas = NULL; return 0; } tasklet_init(&ubc->sent_tasklet, &write_iso_tasklet, (unsigned long) bcs); spin_lock_init(&ubc->isoinlock); for (i = 0; i < BAS_INURBS; ++i) ubc->isoinurbs[i] = NULL; ubc->isoindone = NULL; ubc->loststatus = -EINPROGRESS; ubc->isoinlost = 0; ubc->seqlen = 0; ubc->inbyte = 0; ubc->inbits = 0; ubc->goodbytes = 0; ubc->alignerrs = 0; ubc->fcserrs = 0; ubc->frameerrs = 0; ubc->giants = 0; ubc->runts = 0; ubc->aborts = 0; ubc->shared0s = 0; ubc->stolen0s = 0; tasklet_init(&ubc->rcvd_tasklet, &read_iso_tasklet, (unsigned long) bcs); return 1;}static void gigaset_reinitbcshw(struct bc_state *bcs){ struct bas_bc_state *ubc = bcs->hw.bas; atomic_set(&bcs->hw.bas->running, 0); atomic_set(&bcs->hw.bas->corrbytes, 0); bcs->hw.bas->numsub = 0; spin_lock_init(&ubc->isooutlock); spin_lock_init(&ubc->isoinlock); ubc->loststatus = -EINPROGRESS;}static void gigaset_freecshw(struct cardstate *cs){ /* timers, URBs and rcvbuf are disposed of in disconnect */ kfree(cs->hw.bas); cs->hw.bas = NULL;}static int gigaset_initcshw(struct cardstate *cs){ struct bas_cardstate *ucs; cs->hw.bas = ucs = kmalloc(sizeof *ucs, GFP_KERNEL); if (!ucs) return 0; ucs->urb_cmd_in = NULL; ucs->urb_cmd_out = NULL; ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; spin_lock_init(&ucs->lock); ucs->pending = 0; atomic_set(&ucs->basstate, 0); init_timer(&ucs->timer_ctrl); init_timer(&ucs->timer_atrdy); init_timer(&ucs->timer_cmd_in); return 1;}/* freeurbs * unlink and deallocate all URBs unconditionally * caller must make sure that no commands are still in progress * parameter: * cs controller state structure */static void freeurbs(struct cardstate *cs){ struct bas_cardstate *ucs = cs->hw.bas; struct bas_bc_state *ubc; int i, j; for (j = 0; j < 2; ++j) { ubc = cs->bcs[j].hw.bas; for (i = 0; i < BAS_OUTURBS; ++i) if (ubc->isoouturbs[i].urb) { usb_kill_urb(ubc->isoouturbs[i].urb); gig_dbg(DEBUG_INIT, "%s: isoc output URB %d/%d unlinked", __func__, j, i); usb_free_urb(ubc->isoouturbs[i].urb); ubc->isoouturbs[i].urb = NULL; } for (i = 0; i < BAS_INURBS; ++i) if (ubc->isoinurbs[i]) { usb_kill_urb(ubc->isoinurbs[i]); gig_dbg(DEBUG_INIT, "%s: isoc input URB %d/%d unlinked", __func__, j, i); usb_free_urb(ubc->isoinurbs[i]); ubc->isoinurbs[i] = NULL; } } if (ucs->urb_int_in) { usb_kill_urb(ucs->urb_int_in); gig_dbg(DEBUG_INIT, "%s: interrupt input URB unlinked", __func__); usb_free_urb(ucs->urb_int_in); ucs->urb_int_in = NULL; } if (ucs->urb_cmd_out) { usb_kill_urb(ucs->urb_cmd_out); gig_dbg(DEBUG_INIT, "%s: command output URB unlinked", __func__); usb_free_urb(ucs->urb_cmd_out); ucs->urb_cmd_out = NULL; } if (ucs->urb_cmd_in) { usb_kill_urb(ucs->urb_cmd_in); gig_dbg(DEBUG_INIT, "%s: command input URB unlinked", __func__); usb_free_urb(ucs->urb_cmd_in); ucs->urb_cmd_in = NULL; } if (ucs->urb_ctrl) { usb_kill_urb(ucs->urb_ctrl); gig_dbg(DEBUG_INIT, "%s: control output URB unlinked", __func__); usb_free_urb(ucs->urb_ctrl); ucs->urb_ctrl = NULL; }}/* gigaset_probe * This function is called when a new USB device is connected. * It checks whether the new device is handled by this driver. */static int gigaset_probe(struct usb_interface *interface, const struct usb_device_id *id){ struct usb_host_interface *hostif; struct usb_device *udev = interface_to_usbdev(interface); struct cardstate *cs = NULL; struct bas_cardstate *ucs = NULL; struct bas_bc_state *ubc; struct usb_endpoint_descriptor *endpoint; int i, j; int rc; gig_dbg(DEBUG_ANY, "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", __func__, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); /* set required alternate setting */ hostif = interface->cur_altsetting; if (hostif->desc.bAlternateSetting != 3) { gig_dbg(DEBUG_ANY, "%s: wrong alternate setting %d - trying to switch", __func__, hostif->desc.bAlternateSetting); if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3) < 0) { dev_warn(&udev->dev, "usb_set_interface failed, " "device %d interface %d altsetting %d\n", udev->devnum, hostif->desc.bInterfaceNumber, hostif->desc.bAlternateSetting); return -ENODEV; } hostif = interface->cur_altsetting; } /* Reject application specific interfaces */ if (hostif->desc.bInterfaceClass != 255) { dev_warn(&udev->dev, "%s: bInterfaceClass == %d\n", __func__, hostif->desc.bInterfaceClass); return -ENODEV; } dev_info(&udev->dev, "%s: Device matched (Vendor: 0x%x, Product: 0x%x)\n", __func__, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); cs = gigaset_getunassignedcs(driver); if (!cs) { dev_err(&udev->dev, "no free cardstate\n"); return -ENODEV; } ucs = cs->hw.bas; /* save off device structure ptrs for later use */ usb_get_dev(udev); ucs->udev = udev; ucs->interface = interface; cs->dev = &interface->dev; /* allocate URBs: * - one for the interrupt pipe * - three for the different uses of the default control pipe * - three for each isochronous pipe */ if (!(ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL)) || !(ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL)) || !(ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL)) || !(ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL))) goto allocerr; for (j = 0; j < 2; ++j) { ubc = cs->bcs[j].hw.bas; for (i = 0; i < BAS_OUTURBS; ++i) if (!(ubc->isoouturbs[i].urb = usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL))) goto allocerr; for (i = 0; i < BAS_INURBS; ++i) if (!(ubc->isoinurbs[i] = usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL))) goto allocerr; } ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; /* Fill the interrupt urb and send it to the core */ endpoint = &hostif->endpoint[0].desc; usb_fill_int_urb(ucs->urb_int_in, udev, usb_rcvintpipe(udev, (endpoint->bEndpointAddress) & 0x0f), ucs->int_in_buf, 3, read_int_callback, cs, endpoint->bInterval); if ((rc = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL)) != 0) { dev_err(cs->dev, "could not submit interrupt URB: %s\n", get_usb_rcmsg(rc)); goto error; } /* tell the device that the driver is ready */ if ((rc = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0)) != 0) goto error; /* tell common part that the device is ready */ if (startmode == SM_LOCKED) atomic_set(&cs->mstate, MS_LOCKED); /* save address of controller structure */ usb_set_intfdata(interface, cs); if (!gigaset_start(cs)) goto error; return 0;allocerr: dev_err(cs->dev, "could not allocate URBs\n");error: freeurbs(cs); usb_set_intfdata(interface, NULL); gigaset_unassign(cs); return -ENODEV;}/* gigaset_disconnect * This function is called when the Gigaset base is unplugged. */static void gigaset_disconnect(struct usb_interface *interface){ struct cardstate *cs; struct bas_cardstate *ucs; int j; cs = usb_get_intfdata(interface); ucs = cs->hw.bas; dev_info(cs->dev, "disconnecting Gigaset base\n"); /* mark base as not ready, all channels disconnected */ atomic_set(&ucs->basstate, 0); /* tell LL all channels are down */ //FIXME shouldn't gigaset_stop() do this? for (j = 0; j < 2; ++j) gigaset_bchannel_down(cs->bcs + j); /* stop driver (common part) */ gigaset_stop(cs); /* stop timers and URBs, free ressources */ del_timer_sync(&ucs->timer_ctrl); del_timer_sync(&ucs->timer_atrdy); del_timer_sync(&ucs->timer_cmd_in); freeurbs(cs); usb_set_intfdata(interface, NULL); kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; usb_put_dev(ucs->udev); ucs->interface = NULL; ucs->udev = NULL; cs->dev = NULL; gigaset_unassign(cs);}static struct gigaset_ops gigops = { gigaset_write_cmd, gigaset_write_room, gigaset_chars_in_buffer, gigaset_brkchars, gigaset_init_bchannel, gigaset_close_bchannel, gigaset_initbcshw, gigaset_freebcshw, gigaset_reinitbcshw, gigaset_initcshw, gigaset_freecshw, gigaset_set_modem_ctrl, gigaset_baud_rate, gigaset_set_line_ctrl, gigaset_isoc_send_skb, gigaset_isoc_input,};/* bas_gigaset_init * This function is called after the kernel module is loaded. */static int __init bas_gigaset_init(void){ int result; /* allocate memory for our driver state and intialize it */ if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, GIGASET_DEVFSNAME, &gigops, THIS_MODULE)) == NULL) goto error; /* allocate memory for our device state and intialize it */ cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode, GIGASET_MODULENAME); if (!cardstate) goto error; /* register this driver with the USB subsystem */ result = usb_register(&gigaset_usb_driver); if (result < 0) { err("usb_register failed (error %d)", -result); goto error; } info(DRIVER_AUTHOR); info(DRIVER_DESC); return 0;error: if (cardstate) gigaset_freecs(cardstate); cardstate = NULL; if (driver) gigaset_freedriver(driver); driver = NULL; return -1;}/* bas_gigaset_exit * This function is called before the kernel module is unloaded. */static void __exit bas_gigaset_exit(void){ struct bas_cardstate *ucs = cardstate->hw.bas; gigaset_blockdriver(driver); /* => probe will fail * => no gigaset_start any more */ gigaset_shutdown(cardstate); /* from now on, no isdn callback should be possible */ /* close all still open channels */ if (atomic_read(&ucs->basstate) & BS_B1OPEN) { gig_dbg(DEBUG_INIT, "closing B1 channel"); usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0, NULL, 0, BAS_TIMEOUT); } if (atomic_read(&ucs->basstate) & BS_B2OPEN) { gig_dbg(DEBUG_INIT, "closing B2 channel"); usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0, NULL, 0, BAS_TIMEOUT); } if (atomic_read(&ucs->basstate) & BS_ATOPEN) { gig_dbg(DEBUG_INIT, "closing AT channel"); usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0, NULL, 0, BAS_TIMEOUT); } atomic_set(&ucs->basstate, 0); /* deregister this driver with the USB subsystem */ usb_deregister(&gigaset_usb_driver); /* this will call the disconnect-callback */ /* from now on, no disconnect/probe callback should be running */ gigaset_freecs(cardstate); cardstate = NULL; gigaset_freedriver(driver); driver = NULL;}module_init(bas_gigaset_init);module_exit(bas_gigaset_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?