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

📄 shpchp_hpc.c

📁 audio driver for hotplug pci on linux 2.6.27
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Standard PCI Hot Plug Driver * * Copyright (C) 1995,2001 Compaq Computer Corporation * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001 IBM Corp. * Copyright (C) 2003-2004 Intel Corporation * * 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 program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com> * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/interrupt.h>#include "shpchp.h"/* Slot Available Register I field definition */#define SLOT_33MHZ		0x0000001f#define SLOT_66MHZ_PCIX		0x00001f00#define SLOT_100MHZ_PCIX	0x001f0000#define SLOT_133MHZ_PCIX	0x1f000000/* Slot Available Register II field definition */#define SLOT_66MHZ		0x0000001f#define SLOT_66MHZ_PCIX_266	0x00000f00#define SLOT_100MHZ_PCIX_266	0x0000f000#define SLOT_133MHZ_PCIX_266	0x000f0000#define SLOT_66MHZ_PCIX_533	0x00f00000#define SLOT_100MHZ_PCIX_533	0x0f000000#define SLOT_133MHZ_PCIX_533	0xf0000000/* Slot Configuration */#define SLOT_NUM		0x0000001F#define	FIRST_DEV_NUM		0x00001F00#define PSN			0x07FF0000#define	UPDOWN			0x20000000#define	MRLSENSOR		0x40000000#define ATTN_BUTTON		0x80000000/* * Interrupt Locator Register definitions */#define CMD_INTR_PENDING	(1 << 0)#define SLOT_INTR_PENDING(i)	(1 << (i + 1))/* * Controller SERR-INT Register */#define GLOBAL_INTR_MASK	(1 << 0)#define GLOBAL_SERR_MASK	(1 << 1)#define COMMAND_INTR_MASK	(1 << 2)#define ARBITER_SERR_MASK	(1 << 3)#define COMMAND_DETECTED	(1 << 16)#define ARBITER_DETECTED	(1 << 17)#define SERR_INTR_RSVDZ_MASK	0xfffc0000/* * Logical Slot Register definitions */#define SLOT_REG(i)		(SLOT1 + (4 * i))#define SLOT_STATE_SHIFT	(0)#define SLOT_STATE_MASK		(3 << 0)#define SLOT_STATE_PWRONLY	(1)#define SLOT_STATE_ENABLED	(2)#define SLOT_STATE_DISABLED	(3)#define PWR_LED_STATE_SHIFT	(2)#define PWR_LED_STATE_MASK	(3 << 2)#define ATN_LED_STATE_SHIFT	(4)#define ATN_LED_STATE_MASK	(3 << 4)#define ATN_LED_STATE_ON	(1)#define ATN_LED_STATE_BLINK	(2)#define ATN_LED_STATE_OFF	(3)#define POWER_FAULT		(1 << 6)#define ATN_BUTTON		(1 << 7)#define MRL_SENSOR		(1 << 8)#define MHZ66_CAP		(1 << 9)#define PRSNT_SHIFT		(10)#define PRSNT_MASK		(3 << 10)#define PCIX_CAP_SHIFT		(12)#define PCIX_CAP_MASK_PI1	(3 << 12)#define PCIX_CAP_MASK_PI2	(7 << 12)#define PRSNT_CHANGE_DETECTED	(1 << 16)#define ISO_PFAULT_DETECTED	(1 << 17)#define BUTTON_PRESS_DETECTED	(1 << 18)#define MRL_CHANGE_DETECTED	(1 << 19)#define CON_PFAULT_DETECTED	(1 << 20)#define PRSNT_CHANGE_INTR_MASK	(1 << 24)#define ISO_PFAULT_INTR_MASK	(1 << 25)#define BUTTON_PRESS_INTR_MASK	(1 << 26)#define MRL_CHANGE_INTR_MASK	(1 << 27)#define CON_PFAULT_INTR_MASK	(1 << 28)#define MRL_CHANGE_SERR_MASK	(1 << 29)#define CON_PFAULT_SERR_MASK	(1 << 30)#define SLOT_REG_RSVDZ_MASK	(1 << 15) | (7 << 21)/* * SHPC Command Code definitnions * *     Slot Operation				00h - 3Fh *     Set Bus Segment Speed/Mode A		40h - 47h *     Power-Only All Slots			48h *     Enable All Slots				49h *     Set Bus Segment Speed/Mode B (PI=2)	50h - 5Fh *     Reserved Command Codes			60h - BFh *     Vendor Specific Commands			C0h - FFh */#define SET_SLOT_PWR		0x01	/* Slot Operation */#define SET_SLOT_ENABLE		0x02#define SET_SLOT_DISABLE	0x03#define SET_PWR_ON		0x04#define SET_PWR_BLINK		0x08#define SET_PWR_OFF		0x0c#define SET_ATTN_ON		0x10#define SET_ATTN_BLINK		0x20#define SET_ATTN_OFF		0x30#define SETA_PCI_33MHZ		0x40	/* Set Bus Segment Speed/Mode A */#define SETA_PCI_66MHZ		0x41#define SETA_PCIX_66MHZ		0x42#define SETA_PCIX_100MHZ	0x43#define SETA_PCIX_133MHZ	0x44#define SETA_RESERVED1		0x45#define SETA_RESERVED2		0x46#define SETA_RESERVED3		0x47#define SET_PWR_ONLY_ALL	0x48	/* Power-Only All Slots */#define SET_ENABLE_ALL		0x49	/* Enable All Slots */#define	SETB_PCI_33MHZ		0x50	/* Set Bus Segment Speed/Mode B */#define SETB_PCI_66MHZ		0x51#define SETB_PCIX_66MHZ_PM	0x52#define SETB_PCIX_100MHZ_PM	0x53#define SETB_PCIX_133MHZ_PM	0x54#define SETB_PCIX_66MHZ_EM	0x55#define SETB_PCIX_100MHZ_EM	0x56#define SETB_PCIX_133MHZ_EM	0x57#define SETB_PCIX_66MHZ_266	0x58#define SETB_PCIX_100MHZ_266	0x59#define SETB_PCIX_133MHZ_266	0x5a#define SETB_PCIX_66MHZ_533	0x5b#define SETB_PCIX_100MHZ_533	0x5c#define SETB_PCIX_133MHZ_533	0x5d#define SETB_RESERVED1		0x5e#define SETB_RESERVED2		0x5f/* * SHPC controller command error code */#define SWITCH_OPEN		0x1#define INVALID_CMD		0x2#define INVALID_SPEED_MODE	0x4/* * For accessing SHPC Working Register Set via PCI Configuration Space */#define DWORD_SELECT		0x2#define DWORD_DATA		0x4/* Field Offset in Logical Slot Register - byte boundary */#define SLOT_EVENT_LATCH	0x2#define SLOT_SERR_INT_MASK	0x3static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);static irqreturn_t shpc_isr(int irq, void *dev_id);static void start_int_poll_timer(struct controller *ctrl, int sec);static int hpc_check_cmd_status(struct controller *ctrl);static inline u8 shpc_readb(struct controller *ctrl, int reg){	return readb(ctrl->creg + reg);}static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val){	writeb(val, ctrl->creg + reg);}static inline u16 shpc_readw(struct controller *ctrl, int reg){	return readw(ctrl->creg + reg);}static inline void shpc_writew(struct controller *ctrl, int reg, u16 val){	writew(val, ctrl->creg + reg);}static inline u32 shpc_readl(struct controller *ctrl, int reg){	return readl(ctrl->creg + reg);}static inline void shpc_writel(struct controller *ctrl, int reg, u32 val){	writel(val, ctrl->creg + reg);}static inline int shpc_indirect_read(struct controller *ctrl, int index,				     u32 *value){	int rc;	u32 cap_offset = ctrl->cap_offset;	struct pci_dev *pdev = ctrl->pci_dev;	rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index);	if (rc)		return rc;	return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value);}/* * This is the interrupt polling timeout function. */static void int_poll_timeout(unsigned long data){	struct controller *ctrl = (struct controller *)data;	/* Poll for interrupt events.  regs == NULL => polling */	shpc_isr(0, ctrl);	init_timer(&ctrl->poll_timer);	if (!shpchp_poll_time)		shpchp_poll_time = 2; /* default polling interval is 2 sec */	start_int_poll_timer(ctrl, shpchp_poll_time);}/* * This function starts the interrupt polling timer. */static void start_int_poll_timer(struct controller *ctrl, int sec){	/* Clamp to sane value */	if ((sec <= 0) || (sec > 60))		sec = 2;	ctrl->poll_timer.function = &int_poll_timeout;	ctrl->poll_timer.data = (unsigned long)ctrl;	ctrl->poll_timer.expires = jiffies + sec * HZ;	add_timer(&ctrl->poll_timer);}static inline int is_ctrl_busy(struct controller *ctrl){	u16 cmd_status = shpc_readw(ctrl, CMD_STATUS);	return cmd_status & 0x1;}/* * Returns 1 if SHPC finishes executing a command within 1 sec, * otherwise returns 0. */static inline int shpc_poll_ctrl_busy(struct controller *ctrl){	int i;	if (!is_ctrl_busy(ctrl))		return 1;	/* Check every 0.1 sec for a total of 1 sec */	for (i = 0; i < 10; i++) {		msleep(100);		if (!is_ctrl_busy(ctrl))			return 1;	}	return 0;}static inline int shpc_wait_cmd(struct controller *ctrl){	int retval = 0;	unsigned long timeout = msecs_to_jiffies(1000);	int rc;	if (shpchp_poll_mode)		rc = shpc_poll_ctrl_busy(ctrl);	else		rc = wait_event_interruptible_timeout(ctrl->queue,						!is_ctrl_busy(ctrl), timeout);	if (!rc && is_ctrl_busy(ctrl)) {		retval = -EIO;		err("Command not completed in 1000 msec\n");	} else if (rc < 0) {		retval = -EINTR;		info("Command was interrupted by a signal\n");	}	return retval;}static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd){	struct controller *ctrl = slot->ctrl;	u16 cmd_status;	int retval = 0;	u16 temp_word;	mutex_lock(&slot->ctrl->cmd_lock);	if (!shpc_poll_ctrl_busy(ctrl)) {		/* After 1 sec and and the controller is still busy */		err("%s : Controller is still busy after 1 sec.\n",		    __func__);		retval = -EBUSY;		goto out;	}	++t_slot;	temp_word =  (t_slot << 8) | (cmd & 0xFF);	dbg("%s: t_slot %x cmd %x\n", __func__, t_slot, cmd);	/* To make sure the Controller Busy bit is 0 before we send out the	 * command.	 */	shpc_writew(ctrl, CMD, temp_word);	/*	 * Wait for command completion.	 */	retval = shpc_wait_cmd(slot->ctrl);	if (retval)		goto out;	cmd_status = hpc_check_cmd_status(slot->ctrl);	if (cmd_status) {		err("%s: Failed to issued command 0x%x (error code = %d)\n",		    __func__, cmd, cmd_status);		retval = -EIO;	} out:	mutex_unlock(&slot->ctrl->cmd_lock);	return retval;}static int hpc_check_cmd_status(struct controller *ctrl){	int retval = 0;	u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;	switch (cmd_status >> 1) {	case 0:		retval = 0;		break;	case 1:		retval = SWITCH_OPEN;		err("%s: Switch opened!\n", __func__);		break;	case 2:		retval = INVALID_CMD;		err("%s: Invalid HPC command!\n", __func__);		break;	case 4:		retval = INVALID_SPEED_MODE;		err("%s: Invalid bus speed/mode!\n", __func__);		break;	default:		retval = cmd_status;	}	return retval;}static int hpc_get_attention_status(struct slot *slot, u8 *status){	struct controller *ctrl = slot->ctrl;	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));	u8 state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;	switch (state) {	case ATN_LED_STATE_ON:		*status = 1;	/* On */		break;	case ATN_LED_STATE_BLINK:		*status = 2;	/* Blink */		break;	case ATN_LED_STATE_OFF:		*status = 0;	/* Off */		break;	default:		*status = 0xFF;	/* Reserved */		break;	}	return 0;}static int hpc_get_power_status(struct slot * slot, u8 *status){	struct controller *ctrl = slot->ctrl;	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));	u8 state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;	switch (state) {	case SLOT_STATE_PWRONLY:		*status = 2;	/* Powered only */		break;	case SLOT_STATE_ENABLED:		*status = 1;	/* Enabled */		break;	case SLOT_STATE_DISABLED:		*status = 0;	/* Disabled */		break;	default:		*status = 0xFF;	/* Reserved */		break;	}	return 0;}static int hpc_get_latch_status(struct slot *slot, u8 *status){	struct controller *ctrl = slot->ctrl;	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));	*status = !!(slot_reg & MRL_SENSOR);	/* 0 -> close; 1 -> open */	return 0;}static int hpc_get_adapter_status(struct slot *slot, u8 *status){	struct controller *ctrl = slot->ctrl;	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));	u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;	*status = (state != 0x3) ? 1 : 0;	return 0;}static int hpc_get_prog_int(struct slot *slot, u8 *prog_int){	struct controller *ctrl = slot->ctrl;	*prog_int = shpc_readb(ctrl, PROG_INTERFACE);	return 0;}static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value){	int retval = 0;	struct controller *ctrl = slot->ctrl;	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));	u8 m66_cap  = !!(slot_reg & MHZ66_CAP);	u8 pi, pcix_cap;	if ((retval = hpc_get_prog_int(slot, &pi)))		return retval;	switch (pi) {	case 1:		pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT;		break;	case 2:		pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT;		break;	default:		return -ENODEV;	}	dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n",	    __func__, slot_reg, pcix_cap, m66_cap);	switch (pcix_cap) {	case 0x0:		*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;		break;	case 0x1:		*value = PCI_SPEED_66MHz_PCIX;		break;	case 0x3:		*value = PCI_SPEED_133MHz_PCIX;		break;	case 0x4:		*value = PCI_SPEED_133MHz_PCIX_266;		break;	case 0x5:		*value = PCI_SPEED_133MHz_PCIX_533;		break;	case 0x2:	default:		*value = PCI_SPEED_UNKNOWN;		retval = -ENODEV;		break;	}	dbg("Adapter speed = %d\n", *value);	return retval;}static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode){	int retval = 0;	struct controller *ctrl = slot->ctrl;	u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);	u8 pi = shpc_readb(ctrl, PROG_INTERFACE);	if (pi == 2) {		*mode = (sec_bus_status & 0x0100) >> 8;	} else {		retval = -1;	}	dbg("Mode 1 ECC cap = %d\n", *mode);	return retval;}static int hpc_query_power_fault(struct slot * slot){	struct controller *ctrl = slot->ctrl;	u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));	/* Note: Logic 0 => fault */	return !(slot_reg & POWER_FAULT);}static int hpc_set_attention_status(struct slot *slot, u8 value){	u8 slot_cmd = 0;	switch (value) {		case 0 :			slot_cmd = SET_ATTN_OFF;	/* OFF */			break;		case 1:			slot_cmd = SET_ATTN_ON;		/* ON */			break;		case 2:			slot_cmd = SET_ATTN_BLINK;	/* BLINK */			break;		default:			return -1;	}	return shpc_write_cmd(slot, slot->hp_slot, slot_cmd);}static void hpc_set_green_led_on(struct slot *slot){

⌨️ 快捷键说明

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