⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide-acpi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * ide-acpi.c * Provides ACPI support for IDE drives. * * Copyright (C) 2005 Intel Corp. * Copyright (C) 2005 Randy Dunlap * Copyright (C) 2006 SUSE Linux Products GmbH * Copyright (C) 2006 Hannes Reinecke */#include <linux/ata.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/errno.h>#include <linux/kernel.h>#include <acpi/acpi.h>#include <linux/ide.h>#include <linux/pci.h>#include <linux/dmi.h>#include <acpi/acpi_bus.h>#include <acpi/acnames.h>#include <acpi/acnamesp.h>#include <acpi/acparser.h>#include <acpi/acexcep.h>#include <acpi/acmacros.h>#include <acpi/actypes.h>#define REGS_PER_GTF		7struct taskfile_array {	u8	tfa[REGS_PER_GTF];	/* regs. 0x1f1 - 0x1f7 */};struct GTM_buffer {	u32	PIO_speed0;	u32	DMA_speed0;	u32	PIO_speed1;	u32	DMA_speed1;	u32	GTM_flags;};struct ide_acpi_drive_link {	ide_drive_t	*drive;	acpi_handle	 obj_handle;	u8		 idbuff[512];};struct ide_acpi_hwif_link {	ide_hwif_t			*hwif;	acpi_handle			 obj_handle;	struct GTM_buffer		 gtm;	struct ide_acpi_drive_link	 master;	struct ide_acpi_drive_link	 slave;};#undef DEBUGGING/* note: adds function name and KERN_DEBUG */#ifdef DEBUGGING#define DEBPRINT(fmt, args...)	\		printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)#else#define DEBPRINT(fmt, args...)	do {} while (0)#endif	/* DEBUGGING */extern int ide_noacpi;extern int ide_noacpitfs;extern int ide_noacpionboot;static bool ide_noacpi_psx;static int no_acpi_psx(const struct dmi_system_id *id){	ide_noacpi_psx = true;	printk(KERN_NOTICE"%s detected - disable ACPI _PSx.\n", id->ident);	return 0;}static const struct dmi_system_id ide_acpi_dmi_table[] = {	/* Bug 9673. */	/* We should check if this is because ACPI NVS isn't save/restored. */	{		.callback = no_acpi_psx,		.ident    = "HP nx9005",		.matches  = {			DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies Ltd."),			DMI_MATCH(DMI_BIOS_VERSION, "KAM1.60")		},	},	{ }	/* terminate list */};static int ide_acpi_blacklist(void){	static int done;	if (done)		return 0;	done = 1;	dmi_check_system(ide_acpi_dmi_table);	return 0;}/** * ide_get_dev_handle - finds acpi_handle and PCI device.function * @dev: device to locate * @handle: returned acpi_handle for @dev * @pcidevfn: return PCI device.func for @dev * * Returns the ACPI object handle to the corresponding PCI device. * * Returns 0 on success, <0 on error. */static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,			       acpi_integer *pcidevfn){	struct pci_dev *pdev = to_pci_dev(dev);	unsigned int bus, devnum, func;	acpi_integer addr;	acpi_handle dev_handle;	struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,					.pointer = NULL};	acpi_status status;	struct acpi_device_info	*dinfo = NULL;	int ret = -ENODEV;	bus = pdev->bus->number;	devnum = PCI_SLOT(pdev->devfn);	func = PCI_FUNC(pdev->devfn);	/* ACPI _ADR encoding for PCI bus: */	addr = (acpi_integer)(devnum << 16 | func);	DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);	dev_handle = DEVICE_ACPI_HANDLE(dev);	if (!dev_handle) {		DEBPRINT("no acpi handle for device\n");		goto err;	}	status = acpi_get_object_info(dev_handle, &buffer);	if (ACPI_FAILURE(status)) {		DEBPRINT("get_object_info for device failed\n");		goto err;	}	dinfo = buffer.pointer;	if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&	    dinfo->address == addr) {		*pcidevfn = addr;		*handle = dev_handle;	} else {		DEBPRINT("get_object_info for device has wrong "			" address: %llu, should be %u\n",			dinfo ? (unsigned long long)dinfo->address : -1ULL,			(unsigned int)addr);		goto err;	}	DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",		 devnum, func, (unsigned long long)addr, *handle);	ret = 0;err:	kfree(dinfo);	return ret;}/** * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif * @hwif: device to locate * * Retrieves the object handle for a given hwif. * * Returns handle on success, 0 on error. */static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif){	struct device		*dev = hwif->gendev.parent;	acpi_handle		dev_handle;	acpi_integer		pcidevfn;	acpi_handle		chan_handle;	int			err;	DEBPRINT("ENTER: device %s\n", hwif->name);	if (!dev) {		DEBPRINT("no PCI device for %s\n", hwif->name);		return NULL;	}	err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);	if (err < 0) {		DEBPRINT("ide_get_dev_handle failed (%d)\n", err);		return NULL;	}	/* get child objects of dev_handle == channel objects,	 * + _their_ children == drive objects */	/* channel is hwif->channel */	chan_handle = acpi_get_child(dev_handle, hwif->channel);	DEBPRINT("chan adr=%d: handle=0x%p\n",		 hwif->channel, chan_handle);	return chan_handle;}/** * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive * @drive: device to locate * * Retrieves the object handle of a given drive. According to the ACPI * spec the drive is a child of the hwif. * * Returns handle on success, 0 on error. */static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive){	ide_hwif_t	*hwif = HWIF(drive);	int		 port;	acpi_handle	 drive_handle;	if (!hwif->acpidata)		return NULL;	if (!hwif->acpidata->obj_handle)		return NULL;	port = hwif->channel ? drive->dn - 2: drive->dn;	DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",		 drive->name, hwif->channel, port);	/* TBD: could also check ACPI object VALID bits */	drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);	DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);	return drive_handle;}/** * do_drive_get_GTF - get the drive bootup default taskfile settings * @drive: the drive for which the taskfile settings should be retrieved * @gtf_length: number of bytes of _GTF data returned at @gtf_address * @gtf_address: buffer containing _GTF taskfile arrays * * The _GTF method has no input parameters. * It returns a variable number of register set values (registers * hex 1F1..1F7, taskfiles). * The <variable number> is not known in advance, so have ACPI-CA * allocate the buffer as needed and return it, then free it later. * * The returned @gtf_length and @gtf_address are only valid if the * function return value is 0. */static int do_drive_get_GTF(ide_drive_t *drive,		     unsigned int *gtf_length, unsigned long *gtf_address,		     unsigned long *obj_loc){	acpi_status			status;	struct acpi_buffer		output;	union acpi_object 		*out_obj;	ide_hwif_t			*hwif = HWIF(drive);	struct device			*dev = hwif->gendev.parent;	int				err = -ENODEV;	int				port;	*gtf_length = 0;	*gtf_address = 0UL;	*obj_loc = 0UL;	if (ide_noacpi)		return 0;	if (!dev) {		DEBPRINT("no PCI device for %s\n", hwif->name);		goto out;	}	if (!hwif->acpidata) {		DEBPRINT("no ACPI data for %s\n", hwif->name);		goto out;	}	port = hwif->channel ? drive->dn - 2: drive->dn;	if (!drive->acpidata) {		if (port == 0) {			drive->acpidata = &hwif->acpidata->master;			hwif->acpidata->master.drive = drive;		} else {			drive->acpidata = &hwif->acpidata->slave;			hwif->acpidata->slave.drive = drive;		}	}	DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",		 hwif->name, dev->bus_id, port, hwif->channel);	if (!drive->present) {		DEBPRINT("%s drive %d:%d not present\n",			 hwif->name, hwif->channel, port);		goto out;	}	/* Get this drive's _ADR info. if not already known. */	if (!drive->acpidata->obj_handle) {		drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);		if (!drive->acpidata->obj_handle) {			DEBPRINT("No ACPI object found for %s\n",				 drive->name);			goto out;		}	}	/* Setting up output buffer */	output.length = ACPI_ALLOCATE_BUFFER;	output.pointer = NULL;	/* ACPI-CA sets this; save/free it later */	/* _GTF has no input parameters */	err = -EIO;	status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",				      NULL, &output);	if (ACPI_FAILURE(status)) {		printk(KERN_DEBUG		       "%s: Run _GTF error: status = 0x%x\n",		       __FUNCTION__, status);		goto out;	}	if (!output.length || !output.pointer) {		DEBPRINT("Run _GTF: "		       "length or ptr is NULL (0x%llx, 0x%p)\n",		       (unsigned long long)output.length,		       output.pointer);		goto out;	}	out_obj = output.pointer;	if (out_obj->type != ACPI_TYPE_BUFFER) {		DEBPRINT("Run _GTF: error: "		       "expected object type of ACPI_TYPE_BUFFER, "		       "got 0x%x\n", out_obj->type);		err = -ENOENT;		kfree(output.pointer);		goto out;	}	if (!out_obj->buffer.length || !out_obj->buffer.pointer ||	    out_obj->buffer.length % REGS_PER_GTF) {		printk(KERN_ERR		       "%s: unexpected GTF length (%d) or addr (0x%p)\n",		       __FUNCTION__, out_obj->buffer.length,		       out_obj->buffer.pointer);		err = -ENOENT;		kfree(output.pointer);		goto out;	}	*gtf_length = out_obj->buffer.length;	*gtf_address = (unsigned long)out_obj->buffer.pointer;	*obj_loc = (unsigned long)out_obj;	DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",		 *gtf_length, *gtf_address, *obj_loc);	err = 0;out:	return err;}/** * taskfile_load_raw - send taskfile registers to drive * @drive: drive to which output is sent * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) * * Outputs IDE taskfile to the drive. */static int taskfile_load_raw(ide_drive_t *drive,			      const struct taskfile_array *gtf){	ide_task_t args;	int err = 0;	DEBPRINT("(0x1f1-1f7): hex: "	       "%02x %02x %02x %02x %02x %02x %02x\n",	       gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],	       gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);	memset(&args, 0, sizeof(ide_task_t));	args.command_type = IDE_DRIVE_TASK_NO_DATA;	args.data_phase   = TASKFILE_NO_DATA;	args.handler      = &task_no_data_intr;

⌨️ 快捷键说明

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