static unsigned long __init sun_floppy_init()

in include/asm/floppy_64.h [548:764]


static unsigned long __init sun_floppy_init(void)
{
	static int initialized = 0;
	struct device_node *dp;
	struct platform_device *op;
	const char *prop;
	char state[128];

	if (initialized)
		return sun_floppy_types[0];
	initialized = 1;

	op = NULL;

	for_each_node_by_name(dp, "SUNW,fdtwo") {
		if (!of_node_name_eq(dp->parent, "sbus"))
			continue;
		op = of_find_device_by_node(dp);
		if (op)
			break;
	}
	if (op) {
		floppy_op = op;
		FLOPPY_IRQ = op->archdata.irqs[0];
	} else {
		struct device_node *ebus_dp;
		void __iomem *auxio_reg;
		const char *state_prop;
		unsigned long config;

		dp = NULL;
		for_each_node_by_name(ebus_dp, "ebus") {
			for (dp = ebus_dp->child; dp; dp = dp->sibling) {
				if (ebus_fdthree_p(dp))
					goto found_fdthree;
			}
		}
	found_fdthree:
		if (!dp)
			return 0;

		op = of_find_device_by_node(dp);
		if (!op)
			return 0;

		state_prop = of_get_property(op->dev.of_node, "status", NULL);
		if (state_prop && !strncmp(state_prop, "disabled", 8))
			return 0;

		FLOPPY_IRQ = op->archdata.irqs[0];

		/* Make sure the high density bit is set, some systems
		 * (most notably Ultra5/Ultra10) come up with it clear.
		 */
		auxio_reg = (void __iomem *) op->resource[2].start;
		writel(readl(auxio_reg)|0x2, auxio_reg);

		sun_floppy_dev = &op->dev;

		spin_lock_init(&sun_pci_fd_ebus_dma.lock);

		/* XXX ioremap */
		sun_pci_fd_ebus_dma.regs = (void __iomem *)
			op->resource[1].start;
		if (!sun_pci_fd_ebus_dma.regs)
			return 0;

		sun_pci_fd_ebus_dma.flags = (EBUS_DMA_FLAG_USE_EBDMA_HANDLER |
					     EBUS_DMA_FLAG_TCI_DISABLE);
		sun_pci_fd_ebus_dma.callback = sun_pci_fd_dma_callback;
		sun_pci_fd_ebus_dma.client_cookie = NULL;
		sun_pci_fd_ebus_dma.irq = FLOPPY_IRQ;
		strcpy(sun_pci_fd_ebus_dma.name, "floppy");
		if (ebus_dma_register(&sun_pci_fd_ebus_dma))
			return 0;

		/* XXX ioremap */
		sun_fdc = (struct sun_flpy_controller *) op->resource[0].start;

		sun_fdops.fd_inb = sun_pci_fd_inb;
		sun_fdops.fd_outb = sun_pci_fd_outb;

		can_use_virtual_dma = use_virtual_dma = 0;
		sun_fdops.fd_enable_dma = sun_pci_fd_enable_dma;
		sun_fdops.fd_disable_dma = sun_pci_fd_disable_dma;
		sun_fdops.fd_set_dma_mode = sun_pci_fd_set_dma_mode;
		sun_fdops.fd_set_dma_addr = sun_pci_fd_set_dma_addr;
		sun_fdops.fd_set_dma_count = sun_pci_fd_set_dma_count;
		sun_fdops.get_dma_residue = sun_pci_get_dma_residue;

		sun_fdops.fd_request_irq = sun_pci_fd_request_irq;
		sun_fdops.fd_free_irq = sun_pci_fd_free_irq;

		sun_fdops.fd_eject = sun_pci_fd_eject;

		fdc_status = (unsigned long) &sun_fdc->status_82077;

		/*
		 * XXX: Find out on which machines this is really needed.
		 */
		if (1) {
			sun_pci_broken_drive = 1;
			sun_fdops.fd_outb = sun_pci_fd_broken_outb;
		}

		allowed_drive_mask = 0;
		if (sun_pci_fd_test_drive((unsigned long)sun_fdc, 0))
			sun_floppy_types[0] = 4;
		if (sun_pci_fd_test_drive((unsigned long)sun_fdc, 1))
			sun_floppy_types[1] = 4;

		/*
		 * Find NS87303 SuperIO config registers (through ecpp).
		 */
		config = 0;
		for (dp = ebus_dp->child; dp; dp = dp->sibling) {
			if (of_node_name_eq(dp, "ecpp")) {
				struct platform_device *ecpp_op;

				ecpp_op = of_find_device_by_node(dp);
				if (ecpp_op)
					config = ecpp_op->resource[1].start;
				goto config_done;
			}
		}
	config_done:

		/*
		 * Sanity check, is this really the NS87303?
		 */
		switch (config & 0x3ff) {
		case 0x02e:
		case 0x15c:
		case 0x26e:
		case 0x398:
			break;
		default:
			config = 0;
		}

		if (!config)
			return sun_floppy_types[0];

		/* Enable PC-AT mode. */
		ns87303_modify(config, ASC, 0, 0xc0);

#ifdef PCI_FDC_SWAP_DRIVES
		/*
		 * If only Floppy 1 is present, swap drives.
		 */
		if (!sun_floppy_types[0] && sun_floppy_types[1]) {
			/*
			 * Set the drive exchange bit in FCR on NS87303,
			 * make sure other bits are sane before doing so.
			 */
			ns87303_modify(config, FER, FER_EDM, 0);
			ns87303_modify(config, ASC, ASC_DRV2_SEL, 0);
			ns87303_modify(config, FCR, 0, FCR_LDE);

			config = sun_floppy_types[0];
			sun_floppy_types[0] = sun_floppy_types[1];
			sun_floppy_types[1] = config;

			if (sun_pci_broken_drive != -1) {
				sun_pci_broken_drive = 1 - sun_pci_broken_drive;
				sun_fdops.fd_outb = sun_pci_fd_lde_broken_outb;
			}
		}
#endif /* PCI_FDC_SWAP_DRIVES */

		return sun_floppy_types[0];
	}
	prop = of_get_property(op->dev.of_node, "status", NULL);
	if (prop && !strncmp(state, "disabled", 8))
		return 0;

	/*
	 * We cannot do of_ioremap here: it does request_region,
	 * which the generic floppy driver tries to do once again.
	 * But we must use the sdev resource values as they have
	 * had parent ranges applied.
	 */
	sun_fdc = (struct sun_flpy_controller *)
		(op->resource[0].start +
		 ((op->resource[0].flags & 0x1ffUL) << 32UL));

	/* Last minute sanity check... */
	if (sbus_readb(&sun_fdc->status1_82077) == 0xff) {
		sun_fdc = (struct sun_flpy_controller *)-1;
		return 0;
	}

        sun_fdops.fd_inb = sun_82077_fd_inb;
        sun_fdops.fd_outb = sun_82077_fd_outb;

	can_use_virtual_dma = use_virtual_dma = 1;
	sun_fdops.fd_enable_dma = sun_fd_enable_dma;
	sun_fdops.fd_disable_dma = sun_fd_disable_dma;
	sun_fdops.fd_set_dma_mode = sun_fd_set_dma_mode;
	sun_fdops.fd_set_dma_addr = sun_fd_set_dma_addr;
	sun_fdops.fd_set_dma_count = sun_fd_set_dma_count;
	sun_fdops.get_dma_residue = sun_get_dma_residue;

	sun_fdops.fd_request_irq = sun_fd_request_irq;
	sun_fdops.fd_free_irq = sun_fd_free_irq;

	sun_fdops.fd_eject = sun_fd_eject;

        fdc_status = (unsigned long) &sun_fdc->status_82077;

	/* Success... */
	allowed_drive_mask = 0x01;
	sun_floppy_types[0] = 4;
	sun_floppy_types[1] = 0;

	return sun_floppy_types[0];
}