ricoh_mmc.c

来自「linux 内核源代码」· C语言 代码 · 共 152 行

C
152
字号
/* *  ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller. * *  Copyright (C) 2007 Philip Langdale, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. *//* * This is a conceptually ridiculous driver, but it is required by the way * the Ricoh multi-function R5C832 works. This chip implements firewire * and four different memory card controllers. Two of those controllers are * an SDHCI controller and a proprietary MMC controller. The linux SDHCI * driver supports MMC cards but the chip detects MMC cards in hardware * and directs them to the MMC controller - so the SDHCI driver never sees * them. To get around this, we must disable the useless MMC controller. * At that point, the SDHCI controller will start seeing them. As a bonus, * a detection event occurs immediately, even if the MMC card is already * in the reader. * * The relevant registers live on the firewire function, so this is unavoidably * ugly. Such is life. */#include <linux/pci.h>#define DRIVER_NAME "ricoh-mmc"static const struct pci_device_id pci_ids[] __devinitdata = {	{		.vendor		= PCI_VENDOR_ID_RICOH,		.device		= PCI_DEVICE_ID_RICOH_R5C843,		.subvendor	= PCI_ANY_ID,		.subdevice	= PCI_ANY_ID,	},	{ /* end: all zeroes */ },};MODULE_DEVICE_TABLE(pci, pci_ids);static int __devinit ricoh_mmc_probe(struct pci_dev *pdev,				     const struct pci_device_id *ent){	u8 rev;	struct pci_dev *fw_dev = NULL;	BUG_ON(pdev == NULL);	BUG_ON(ent == NULL);	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);	printk(KERN_INFO DRIVER_NAME		": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n",		pci_name(pdev), (int)pdev->vendor, (int)pdev->device,		(int)rev);	while ((fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) {		if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&		    pdev->bus == fw_dev->bus) {			u8 write_enable;			u8 disable;			pci_read_config_byte(fw_dev, 0xCB, &disable);			if (disable & 0x02) {				printk(KERN_INFO DRIVER_NAME				       ": Controller already disabled. Nothing to do.\n");				return -ENODEV;			}			pci_read_config_byte(fw_dev, 0xCA, &write_enable);			pci_write_config_byte(fw_dev, 0xCA, 0x57);			pci_write_config_byte(fw_dev, 0xCB, disable | 0x02);			pci_write_config_byte(fw_dev, 0xCA, write_enable);			pci_set_drvdata(pdev, fw_dev);			printk(KERN_INFO DRIVER_NAME			       ": Controller is now disabled.\n");			break;		}	}	if (pci_get_drvdata(pdev) == NULL) {		printk(KERN_WARNING DRIVER_NAME		       ": Main firewire function not found. Cannot disable controller.\n");		return -ENODEV;	}	return 0;}static void __devexit ricoh_mmc_remove(struct pci_dev *pdev){	u8 write_enable;	u8 disable;	struct pci_dev *fw_dev = NULL;	fw_dev = pci_get_drvdata(pdev);	BUG_ON(fw_dev == NULL);	pci_read_config_byte(fw_dev, 0xCA, &write_enable);	pci_read_config_byte(fw_dev, 0xCB, &disable);	pci_write_config_byte(fw_dev, 0xCA, 0x57);	pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02);	pci_write_config_byte(fw_dev, 0xCA, write_enable);	printk(KERN_INFO DRIVER_NAME	       ": Controller is now re-enabled.\n");	pci_set_drvdata(pdev, NULL);}static struct pci_driver ricoh_mmc_driver = {	.name = 	DRIVER_NAME,	.id_table =	pci_ids,	.probe = 	ricoh_mmc_probe,	.remove =	__devexit_p(ricoh_mmc_remove),};/*****************************************************************************\ *                                                                           * * Driver init/exit                                                          * *                                                                           *\*****************************************************************************/static int __init ricoh_mmc_drv_init(void){	printk(KERN_INFO DRIVER_NAME		": Ricoh MMC Controller disabling driver\n");	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n");	return pci_register_driver(&ricoh_mmc_driver);}static void __exit ricoh_mmc_drv_exit(void){	pci_unregister_driver(&ricoh_mmc_driver);}module_init(ricoh_mmc_drv_init);module_exit(ricoh_mmc_drv_exit);MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>");MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?