usb-gigaset.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 962 行 · 第 1/2 页
C
962 行
cb->buf + cb->offset, count, gigaset_write_bulk_callback, cs); cb->offset += count; cb->len -= count; atomic_set(&ucs->busy, 1); spin_lock_irqsave(&cs->lock, flags); status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC) : -ENODEV; spin_unlock_irqrestore(&cs->lock, flags); if (status) { atomic_set(&ucs->busy, 0); err("could not submit urb (error %d)\n", -status); cb->len = 0; /* skip urb => remove cb+wakeup in next loop cycle */ } } } while (cb && status); /* next command on error */ return status;}/* Send command to device. */static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, int len, struct tasklet_struct *wake_tasklet){ struct cmdbuf_t *cb; unsigned long flags; gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? DEBUG_TRANSCMD : DEBUG_LOCKCMD, "CMD Transmit", len, buf); if (len <= 0) return 0; if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { dev_err(cs->dev, "%s: out of memory\n", __func__); return -ENOMEM; } memcpy(cb->buf, buf, len); cb->len = len; cb->offset = 0; cb->next = NULL; cb->wake_tasklet = wake_tasklet; spin_lock_irqsave(&cs->cmdlock, flags); cb->prev = cs->lastcmdbuf; if (cs->lastcmdbuf) cs->lastcmdbuf->next = cb; else { cs->cmdbuf = cb; cs->curlen = len; } cs->cmdbytes += len; cs->lastcmdbuf = cb; spin_unlock_irqrestore(&cs->cmdlock, flags); spin_lock_irqsave(&cs->lock, flags); if (cs->connected) tasklet_schedule(&cs->write_tasklet); spin_unlock_irqrestore(&cs->lock, flags); return len;}static int gigaset_write_room(struct cardstate *cs){ unsigned long flags; unsigned bytes; spin_lock_irqsave(&cs->cmdlock, flags); bytes = cs->cmdbytes; spin_unlock_irqrestore(&cs->cmdlock, flags); return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0;}static int gigaset_chars_in_buffer(struct cardstate *cs){ return cs->cmdbytes;}static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]){#ifdef CONFIG_GIGASET_UNDOCREQ struct usb_device *udev = cs->hw.usb->udev; gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf); memcpy(cs->hw.usb->bchars, buf, 6); return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, 0, 0, &buf, 6, 2000);#else return -EINVAL;#endif}static int gigaset_freebcshw(struct bc_state *bcs){ if (!bcs->hw.usb) return 0; //FIXME kfree(bcs->hw.usb); return 1;}/* Initialize the b-channel structure */static int gigaset_initbcshw(struct bc_state *bcs){ bcs->hw.usb = kmalloc(sizeof(struct usb_bc_state), GFP_KERNEL); if (!bcs->hw.usb) return 0; return 1;}static void gigaset_reinitbcshw(struct bc_state *bcs){}static void gigaset_freecshw(struct cardstate *cs){ tasklet_kill(&cs->write_tasklet); kfree(cs->hw.usb);}static int gigaset_initcshw(struct cardstate *cs){ struct usb_cardstate *ucs; cs->hw.usb = ucs = kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL); if (!ucs) return 0; ucs->bchars[0] = 0; ucs->bchars[1] = 0; ucs->bchars[2] = 0; ucs->bchars[3] = 0; ucs->bchars[4] = 0x11; ucs->bchars[5] = 0x13; ucs->bulk_out_buffer = NULL; ucs->bulk_out_urb = NULL; //ucs->urb_cmd_out = NULL; ucs->read_urb = NULL; tasklet_init(&cs->write_tasklet, &gigaset_modem_fill, (unsigned long) cs); return 1;}/* Send data from current skb to the device. */static int write_modem(struct cardstate *cs){ int ret = 0; int count; struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ struct usb_cardstate *ucs = cs->hw.usb; unsigned long flags; gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len); if (!bcs->tx_skb->len) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; return -EINVAL; } /* Copy data to bulk out buffer and // FIXME copying not necessary * transmit data */ count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count); skb_pull(bcs->tx_skb, count); atomic_set(&ucs->busy, 1); gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); spin_lock_irqsave(&cs->lock, flags); if (cs->connected) { usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, usb_sndbulkpipe(ucs->udev, ucs->bulk_out_endpointAddr & 0x0f), ucs->bulk_out_buffer, count, gigaset_write_bulk_callback, cs); ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); } else { ret = -ENODEV; } spin_unlock_irqrestore(&cs->lock, flags); if (ret) { err("could not submit urb (error %d)\n", -ret); atomic_set(&ucs->busy, 0); } if (!bcs->tx_skb->len) { /* skb sent completely */ gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0? gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!", (unsigned long) bcs->tx_skb); dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } return ret;}static int gigaset_probe(struct usb_interface *interface, const struct usb_device_id *id){ int retval; struct usb_device *udev = interface_to_usbdev(interface); unsigned int ifnum; struct usb_host_interface *hostif; struct cardstate *cs = NULL; struct usb_cardstate *ucs = NULL; struct usb_endpoint_descriptor *endpoint; int buffer_size; int alt; 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)); retval = -ENODEV; //FIXME /* See if the device offered us matches what we can accept */ if ((le16_to_cpu(udev->descriptor.idVendor) != USB_M105_VENDOR_ID) || (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) return -ENODEV; /* this starts to become ascii art... */ hostif = interface->cur_altsetting; alt = hostif->desc.bAlternateSetting; ifnum = hostif->desc.bInterfaceNumber; // FIXME ? if (alt != 0 || ifnum != 0) { dev_warn(&udev->dev, "ifnum %d, alt %d\n", ifnum, alt); return -ENODEV; } /* Reject application specific intefaces * */ if (hostif->desc.bInterfaceClass != 255) { dev_info(&udev->dev, "%s: Device matched but iface_desc[%d]->bInterfaceClass==%d!\n", __func__, ifnum, hostif->desc.bInterfaceClass); return -ENODEV; } dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); cs = gigaset_getunassignedcs(driver); if (!cs) { dev_warn(&udev->dev, "no free cardstate\n"); return -ENODEV; } ucs = cs->hw.usb; /* save off device structure ptrs for later use */ usb_get_dev(udev); ucs->udev = udev; ucs->interface = interface; cs->dev = &interface->dev; /* save address of controller structure */ usb_set_intfdata(interface, cs); // dev_set_drvdata(&interface->dev, cs); endpoint = &hostif->endpoint[0].desc; buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); ucs->bulk_out_size = buffer_size; ucs->bulk_out_endpointAddr = endpoint->bEndpointAddress; ucs->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!ucs->bulk_out_buffer) { dev_err(cs->dev, "Couldn't allocate bulk_out_buffer\n"); retval = -ENOMEM; goto error; } ucs->bulk_out_urb = usb_alloc_urb(0, SLAB_KERNEL); if (!ucs->bulk_out_urb) { dev_err(cs->dev, "Couldn't allocate bulk_out_urb\n"); retval = -ENOMEM; goto error; } endpoint = &hostif->endpoint[1].desc; atomic_set(&ucs->busy, 0); ucs->read_urb = usb_alloc_urb(0, SLAB_KERNEL); if (!ucs->read_urb) { dev_err(cs->dev, "No free urbs available\n"); retval = -ENOMEM; goto error; } buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); ucs->rcvbuf_size = buffer_size; ucs->int_in_endpointAddr = endpoint->bEndpointAddress; cs->inbuf[0].rcvbuf = kmalloc(buffer_size, GFP_KERNEL); if (!cs->inbuf[0].rcvbuf) { dev_err(cs->dev, "Couldn't allocate rcvbuf\n"); retval = -ENOMEM; goto error; } /* Fill the interrupt urb and send it to the core */ usb_fill_int_urb(ucs->read_urb, udev, usb_rcvintpipe(udev, endpoint->bEndpointAddress & 0x0f), cs->inbuf[0].rcvbuf, buffer_size, gigaset_read_int_callback, cs->inbuf + 0, endpoint->bInterval); retval = usb_submit_urb(ucs->read_urb, SLAB_KERNEL); if (retval) { dev_err(cs->dev, "Could not submit URB (error %d)\n", -retval); goto error; } /* tell common part that the device is ready */ if (startmode == SM_LOCKED) atomic_set(&cs->mstate, MS_LOCKED); if (!gigaset_start(cs)) { tasklet_kill(&cs->write_tasklet); retval = -ENODEV; //FIXME goto error; } return 0;error: if (ucs->read_urb) usb_kill_urb(ucs->read_urb); kfree(ucs->bulk_out_buffer); if (ucs->bulk_out_urb != NULL) usb_free_urb(ucs->bulk_out_urb); kfree(cs->inbuf[0].rcvbuf); if (ucs->read_urb != NULL) usb_free_urb(ucs->read_urb); usb_set_intfdata(interface, NULL); ucs->read_urb = ucs->bulk_out_urb = NULL; cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; usb_put_dev(ucs->udev); ucs->udev = NULL; ucs->interface = NULL; gigaset_unassign(cs); return retval;}static void gigaset_disconnect(struct usb_interface *interface){ struct cardstate *cs; struct usb_cardstate *ucs; cs = usb_get_intfdata(interface); ucs = cs->hw.usb; usb_kill_urb(ucs->read_urb); gigaset_stop(cs); usb_set_intfdata(interface, NULL); tasklet_kill(&cs->write_tasklet); usb_kill_urb(ucs->bulk_out_urb); /* FIXME: only if active? */ kfree(ucs->bulk_out_buffer); if (ucs->bulk_out_urb != NULL) usb_free_urb(ucs->bulk_out_urb); kfree(cs->inbuf[0].rcvbuf); if (ucs->read_urb != NULL) usb_free_urb(ucs->read_urb); ucs->read_urb = ucs->bulk_out_urb = NULL; cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; usb_put_dev(ucs->udev); ucs->interface = NULL; ucs->udev = NULL; cs->dev = NULL; gigaset_unassign(cs);}static struct gigaset_ops ops = { 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_m10x_send_skb, gigaset_m10x_input,};/** * usb_gigaset_init * This function is called while kernel-module is loaded */static int __init usb_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, &ops, THIS_MODULE)) == NULL) goto error; /* allocate memory for our device state and intialize it */ cardstate = gigaset_initcs(driver, 1, 1, 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_gigaset: 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;}/** * usb_gigaset_exit * This function is called while unloading the kernel-module */static void __exit usb_gigaset_exit(void){ gigaset_blockdriver(driver); /* => probe will fail * => no gigaset_start any more */ gigaset_shutdown(cardstate); /* from now on, no isdn callback should be possible */ /* 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(usb_gigaset_init);module_exit(usb_gigaset_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?