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 + -
显示快捷键?