pc87427.c

来自「linux 内核源代码」· C语言 代码 · 共 641 行 · 第 1/2 页

C
641
字号
		&sensor_dev_attr_fan2_alarm.dev_attr.attr,		&sensor_dev_attr_fan2_fault.dev_attr.attr,		NULL	}, {		&sensor_dev_attr_fan3_input.dev_attr.attr,		&sensor_dev_attr_fan3_min.dev_attr.attr,		&sensor_dev_attr_fan3_alarm.dev_attr.attr,		&sensor_dev_attr_fan3_fault.dev_attr.attr,		NULL	}, {		&sensor_dev_attr_fan4_input.dev_attr.attr,		&sensor_dev_attr_fan4_min.dev_attr.attr,		&sensor_dev_attr_fan4_alarm.dev_attr.attr,		&sensor_dev_attr_fan4_fault.dev_attr.attr,		NULL	}, {		&sensor_dev_attr_fan5_input.dev_attr.attr,		&sensor_dev_attr_fan5_min.dev_attr.attr,		&sensor_dev_attr_fan5_alarm.dev_attr.attr,		&sensor_dev_attr_fan5_fault.dev_attr.attr,		NULL	}, {		&sensor_dev_attr_fan6_input.dev_attr.attr,		&sensor_dev_attr_fan6_min.dev_attr.attr,		&sensor_dev_attr_fan6_alarm.dev_attr.attr,		&sensor_dev_attr_fan6_fault.dev_attr.attr,		NULL	}, {		&sensor_dev_attr_fan7_input.dev_attr.attr,		&sensor_dev_attr_fan7_min.dev_attr.attr,		&sensor_dev_attr_fan7_alarm.dev_attr.attr,		&sensor_dev_attr_fan7_fault.dev_attr.attr,		NULL	}, {		&sensor_dev_attr_fan8_input.dev_attr.attr,		&sensor_dev_attr_fan8_min.dev_attr.attr,		&sensor_dev_attr_fan8_alarm.dev_attr.attr,		&sensor_dev_attr_fan8_fault.dev_attr.attr,		NULL	}};static const struct attribute_group pc87427_group_fan[8] = {	{ .attrs = pc87427_attributes_fan[0] },	{ .attrs = pc87427_attributes_fan[1] },	{ .attrs = pc87427_attributes_fan[2] },	{ .attrs = pc87427_attributes_fan[3] },	{ .attrs = pc87427_attributes_fan[4] },	{ .attrs = pc87427_attributes_fan[5] },	{ .attrs = pc87427_attributes_fan[6] },	{ .attrs = pc87427_attributes_fan[7] },};static ssize_t show_name(struct device *dev, struct device_attribute			 *devattr, char *buf){	struct pc87427_data *data = dev_get_drvdata(dev);	return sprintf(buf, "%s\n", data->name);}static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);/* * Device detection, attach and detach */static void __devinit pc87427_init_device(struct device *dev){	struct pc87427_data *data = dev_get_drvdata(dev);	int i;	u8 reg;	/* The FMC module should be ready */	reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK);	if (!(reg & 0x80))		dev_warn(dev, "FMC module not ready!\n");	/* Check which fans are enabled */	for (i = 0; i < 8; i++) {		reg = pc87427_read8_bank(data, LD_FAN, BANK_FM(i),					 PC87427_REG_FAN_STATUS);		if (reg & FAN_STATUS_MONEN)			data->fan_enabled |= (1 << i);	}	if (!data->fan_enabled) {		dev_dbg(dev, "Enabling all fan inputs\n");		for (i = 0; i < 8; i++)			pc87427_write8_bank(data, LD_FAN, BANK_FM(i),					    PC87427_REG_FAN_STATUS,					    FAN_STATUS_MONEN);		data->fan_enabled = 0xff;	}}static int __devinit pc87427_probe(struct platform_device *pdev){	struct pc87427_data *data;	struct resource *res;	int i, err;	if (!(data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL))) {		err = -ENOMEM;		printk(KERN_ERR DRVNAME ": Out of memory\n");		goto exit;	}	/* This will need to be revisited when we add support for	   temperature and voltage monitoring. */	res = platform_get_resource(pdev, IORESOURCE_IO, 0);	if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {		err = -EBUSY;		dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",			(unsigned long)res->start, (unsigned long)res->end);		goto exit_kfree;	}	data->address[0] = res->start;	mutex_init(&data->lock);	data->name = "pc87427";	platform_set_drvdata(pdev, data);	pc87427_init_device(&pdev->dev);	/* Register sysfs hooks */	if ((err = device_create_file(&pdev->dev, &dev_attr_name)))		goto exit_release_region;	for (i = 0; i < 8; i++) {		if (!(data->fan_enabled & (1 << i)))			continue;		if ((err = sysfs_create_group(&pdev->dev.kobj,					      &pc87427_group_fan[i])))			goto exit_remove_files;	}	data->hwmon_dev = hwmon_device_register(&pdev->dev);	if (IS_ERR(data->hwmon_dev)) {		err = PTR_ERR(data->hwmon_dev);		dev_err(&pdev->dev, "Class registration failed (%d)\n", err);		goto exit_remove_files;	}	return 0;exit_remove_files:	for (i = 0; i < 8; i++) {		if (!(data->fan_enabled & (1 << i)))			continue;		sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);	}exit_release_region:	release_region(res->start, res->end - res->start + 1);exit_kfree:	platform_set_drvdata(pdev, NULL);	kfree(data);exit:	return err;}static int __devexit pc87427_remove(struct platform_device *pdev){	struct pc87427_data *data = platform_get_drvdata(pdev);	struct resource *res;	int i;	hwmon_device_unregister(data->hwmon_dev);	device_remove_file(&pdev->dev, &dev_attr_name);	for (i = 0; i < 8; i++) {		if (!(data->fan_enabled & (1 << i)))			continue;		sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);	}	platform_set_drvdata(pdev, NULL);	kfree(data);	res = platform_get_resource(pdev, IORESOURCE_IO, 0);	release_region(res->start, res->end - res->start + 1);	return 0;}static struct platform_driver pc87427_driver = {	.driver = {		.owner	= THIS_MODULE,		.name	= DRVNAME,	},	.probe		= pc87427_probe,	.remove		= __devexit_p(pc87427_remove),};static int __init pc87427_device_add(unsigned short address){	struct resource res = {		.start	= address,		.end	= address + REGION_LENGTH - 1,		.name	= logdev_str[0],		.flags	= IORESOURCE_IO,	};	int err;	pdev = platform_device_alloc(DRVNAME, address);	if (!pdev) {		err = -ENOMEM;		printk(KERN_ERR DRVNAME ": Device allocation failed\n");		goto exit;	}	err = platform_device_add_resources(pdev, &res, 1);	if (err) {		printk(KERN_ERR DRVNAME ": Device resource addition failed "		       "(%d)\n", err);		goto exit_device_put;	}	err = platform_device_add(pdev);	if (err) {		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",		       err);		goto exit_device_put;	}	return 0;exit_device_put:	platform_device_put(pdev);exit:	return err;}static int __init pc87427_find(int sioaddr, unsigned short *address){	u16 val;	int i, err = 0;	/* Identify device */	val = superio_inb(sioaddr, SIOREG_DEVID);	if (val != 0xf2) {	/* PC87427 */		err = -ENODEV;		goto exit;	}	for (i = 0; i < 2; i++) {		address[i] = 0;		/* Select logical device */		superio_outb(sioaddr, SIOREG_LDSEL, logdev[i]);		val = superio_inb(sioaddr, SIOREG_ACT);		if (!(val & 0x01)) {			printk(KERN_INFO DRVNAME ": Logical device 0x%02x "			       "not activated\n", logdev[i]);			continue;		}		val = superio_inb(sioaddr, SIOREG_MAP);		if (val & 0x01) {			printk(KERN_WARNING DRVNAME ": Logical device 0x%02x "			       "is memory-mapped, can't use\n", logdev[i]);			continue;		}		val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)		    | superio_inb(sioaddr, SIOREG_IOBASE + 1);		if (!val) {			printk(KERN_INFO DRVNAME ": I/O base address not set "			       "for logical device 0x%02x\n", logdev[i]);			continue;		}		address[i] = val;	}exit:	superio_exit(sioaddr);	return err;}static int __init pc87427_init(void){	int err;	unsigned short address[2];	if (pc87427_find(0x2e, address)	 && pc87427_find(0x4e, address))		return -ENODEV;	/* For now the driver only handles fans so we only care about the	   first address. */	if (!address[0])		return -ENODEV;	err = platform_driver_register(&pc87427_driver);	if (err)		goto exit;	/* Sets global pdev as a side effect */	err = pc87427_device_add(address[0]);	if (err)		goto exit_driver;	return 0;exit_driver:	platform_driver_unregister(&pc87427_driver);exit:	return err;}static void __exit pc87427_exit(void){	platform_device_unregister(pdev);	platform_driver_unregister(&pc87427_driver);}MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");MODULE_DESCRIPTION("PC87427 hardware monitoring driver");MODULE_LICENSE("GPL");module_init(pc87427_init);module_exit(pc87427_exit);

⌨️ 快捷键说明

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