Commit f2362c94 authored by Jiri Slaby's avatar Jiri Slaby Committed by Linus Torvalds
Browse files

[PATCH] Char: istallion, change init sequence



Reorganizate module init and exit and implement logic, when something fails in
these functions.  The former is needed for proper handling dynamic
tty_register_device.

Signed-off-by: default avatarJiri Slaby <jirislaby@gmail.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f1cc54f8
Loading
Loading
Loading
Loading
+75 −55
Original line number Diff line number Diff line
@@ -4545,46 +4545,49 @@ static const struct tty_operations stli_ops = {
 *	Loadable module initialization stuff.
 */

static void istallion_cleanup_isa(void)
{
	struct stlibrd	*brdp;
	unsigned int j;

	for (j = 0; (j < stli_nrbrds); j++) {
		if ((brdp = stli_brds[j]) == NULL || (brdp->state & BST_PROBED))
			continue;

		stli_cleanup_ports(brdp);

		iounmap(brdp->membase);
		if (brdp->iosize > 0)
			release_region(brdp->iobase, brdp->iosize);
		kfree(brdp);
		stli_brds[j] = NULL;
	}
}

static int __init istallion_module_init(void)
{
	int i;
	unsigned int i;
	int retval;

	printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);

	spin_lock_init(&stli_lock);
	spin_lock_init(&brd_lock);

	stli_initbrds();

	stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
	if (!stli_serial)
		return -ENOMEM;

/*
 *	Allocate a temporary write buffer.
 */
	stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
	if (!stli_txcookbuf)
	if (!stli_txcookbuf) {
		printk(KERN_ERR "STALLION: failed to allocate memory "
				"(size=%d)\n", STLI_TXBUFSIZE);
		retval = -ENOMEM;
		goto err;
	}

/*
 *	Set up a character driver for the shared memory region. We need this
 *	to down load the slave code image. Also it is a useful debugging tool.
 */
	if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem))
		printk(KERN_ERR "STALLION: failed to register serial memory "
				"device\n");

	istallion_class = class_create(THIS_MODULE, "staliomem");
	for (i = 0; i < 4; i++)
		class_device_create(istallion_class, NULL,
				MKDEV(STL_SIOMEMMAJOR, i),
				NULL, "staliomem%d", i);
	stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
	if (!stli_serial) {
		retval = -ENOMEM;
		goto err_free;
	}

/*
 *	Set up the tty driver structure and register us as a driver.
 */
	stli_serial->owner = THIS_MODULE;
	stli_serial->driver_name = stli_drvname;
	stli_serial->name = stli_serialname;
@@ -4596,58 +4599,75 @@ static int __init istallion_module_init(void)
	stli_serial->flags = TTY_DRIVER_REAL_RAW;
	tty_set_operations(stli_serial, &stli_ops);

	if (tty_register_driver(stli_serial)) {
		put_tty_driver(stli_serial);
	retval = tty_register_driver(stli_serial);
	if (retval) {
		printk(KERN_ERR "STALLION: failed to register serial driver\n");
		return -EBUSY;
		goto err_ttyput;
	}

	retval = stli_initbrds();
	if (retval)
		goto err_ttyunr;

/*
 *	Set up a character driver for the shared memory region. We need this
 *	to down load the slave code image. Also it is a useful debugging tool.
 */
	retval = register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem);
	if (retval) {
		printk(KERN_ERR "STALLION: failed to register serial memory "
				"device\n");
		goto err_deinit;
	}

	istallion_class = class_create(THIS_MODULE, "staliomem");
	for (i = 0; i < 4; i++)
		class_device_create(istallion_class, NULL,
				MKDEV(STL_SIOMEMMAJOR, i),
				NULL, "staliomem%d", i);

	return 0;
err_deinit:
	pci_unregister_driver(&stli_pcidriver);
	istallion_cleanup_isa();
err_ttyunr:
	tty_unregister_driver(stli_serial);
err_ttyput:
	put_tty_driver(stli_serial);
err_free:
	kfree(stli_txcookbuf);
err:
	return retval;
}

/*****************************************************************************/

static void __exit istallion_module_exit(void)
{
	struct stlibrd	*brdp;
	unsigned int j;
	int		i;

	printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
		stli_drvversion);

	pci_unregister_driver(&stli_pcidriver);
	/*
	 *	Free up all allocated resources used by the ports. This includes
	 *	memory and interrupts.
	 */
	if (stli_timeron) {
		stli_timeron = 0;
		del_timer_sync(&stli_timerlist);
	}

	i = tty_unregister_driver(stli_serial);
	put_tty_driver(stli_serial);
	unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");

	for (j = 0; j < 4; j++)
		class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j));
		class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR,
					j));
	class_destroy(istallion_class);
	if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
		printk("STALLION: failed to un-register serial memory device, "
			"errno=%d\n", -i);

	kfree(stli_txcookbuf);

	for (j = 0; (j < stli_nrbrds); j++) {
		if ((brdp = stli_brds[j]) == NULL || (brdp->state & BST_PROBED))
			continue;
	pci_unregister_driver(&stli_pcidriver);
	istallion_cleanup_isa();

		stli_cleanup_ports(brdp);
	tty_unregister_driver(stli_serial);
	put_tty_driver(stli_serial);

		iounmap(brdp->membase);
		if (brdp->iosize > 0)
			release_region(brdp->iobase, brdp->iosize);
		kfree(brdp);
		stli_brds[j] = NULL;
	}
	kfree(stli_txcookbuf);
}

module_init(istallion_module_init);