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