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

📄 via-pmu.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Device driver for the via-pmu on Apple Powermacs. * * The VIA (versatile interface adapter) interfaces to the PMU, * a 6805 microprocessor core whose primary function is to control * battery charging and system power on the PowerBook 3400 and 2400. * The PMU also controls the ADB (Apple Desktop Bus) which connects * to the keyboard and mouse, as well as the non-volatile RAM * and the RTC (real time clock) chip. * * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. *  * todo: - Check this driver for smp safety (new Core99 motherboards). *       - Cleanup synchro between VIA interrupt and GPIO-based PMU *         interrupt. * * */#include <stdarg.h>#include <linux/config.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/miscdevice.h>#include <linux/blkdev.h>#include <linux/pci.h>#include <linux/malloc.h>#include <linux/poll.h>#include <linux/adb.h>#include <linux/pmu.h>#include <linux/cuda.h>#include <linux/smp_lock.h>#include <linux/spinlock.h>#include <asm/prom.h>#include <asm/machdep.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/init.h>#include <asm/irq.h>#include <asm/hardirq.h>#include <asm/feature.h>#include <asm/uaccess.h>#include <asm/mmu_context.h>#ifdef CONFIG_PMAC_BACKLIGHT#include <asm/backlight.h>#endif/* Some compile options */#undef SUSPEND_USES_PMU/* Misc minor number allocated for /dev/pmu */#define PMU_MINOR	154static volatile unsigned char *via;/* VIA registers - spaced 0x200 bytes apart */#define RS		0x200		/* skip between registers */#define B		0		/* B-side data */#define A		RS		/* A-side data */#define DIRB		(2*RS)		/* B-side direction (1=output) */#define DIRA		(3*RS)		/* A-side direction (1=output) */#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */#define T2CL		(8*RS)		/* Timer 2 ctr/latch (low 8 bits) */#define T2CH		(9*RS)		/* Timer 2 counter (high 8 bits) */#define SR		(10*RS)		/* Shift register */#define ACR		(11*RS)		/* Auxiliary control register */#define PCR		(12*RS)		/* Peripheral control register */#define IFR		(13*RS)		/* Interrupt flag register */#define IER		(14*RS)		/* Interrupt enable register */#define ANH		(15*RS)		/* A-side data, no handshake *//* Bits in B data register: both active low */#define TACK		0x08		/* Transfer acknowledge (input) */#define TREQ		0x10		/* Transfer request (output) *//* Bits in ACR */#define SR_CTRL		0x1c		/* Shift register control bits */#define SR_EXT		0x0c		/* Shift on external clock */#define SR_OUT		0x10		/* Shift out if 1 *//* Bits in IFR and IER */#define IER_SET		0x80		/* set bits in IER */#define IER_CLR		0		/* clear bits in IER */#define SR_INT		0x04		/* Shift register full/empty */#define CB2_INT		0x08#define CB1_INT		0x10		/* transition on CB1 input */static volatile enum pmu_state {	idle,	sending,	intack,	reading,	reading_intr,} pmu_state;static struct adb_request *current_req;static struct adb_request *last_req;static struct adb_request *req_awaiting_reply;static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */static unsigned char *reply_ptr;static int data_index;static int data_len;static volatile int adb_int_pending;static int pmu_adb_flags;static int adb_dev_map = 0;static struct adb_request bright_req_1, bright_req_2, bright_req_3;static struct device_node *vias;static int pmu_kind = PMU_UNKNOWN;static int pmu_fully_inited = 0;static int pmu_has_adb;static unsigned char *gpio_reg = NULL;static int gpio_irq = -1;static volatile int pmu_suspended = 0;static spinlock_t pmu_lock;int asleep;struct notifier_block *sleep_notifier_list;#ifdef CONFIG_ADBstatic int pmu_probe(void);static int pmu_init(void);static int pmu_send_request(struct adb_request *req, int sync);static int pmu_adb_autopoll(int devs);static int pmu_adb_reset_bus(void);#endif /* CONFIG_ADB */static int init_pmu(void);static int pmu_queue_request(struct adb_request *req);static void pmu_start(void);static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);static void send_byte(int x);static void recv_byte(void);static void pmu_sr_intr(struct pt_regs *regs);static void pmu_done(struct adb_request *req);static void pmu_handle_data(unsigned char *data, int len,			    struct pt_regs *regs);static void set_volume(int level);static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);#ifdef CONFIG_PMAC_BACKLIGHTstatic int pmu_set_backlight_level(int level, void* data);static int pmu_set_backlight_enable(int on, int level, void* data);#endif /* CONFIG_PMAC_BACKLIGHT */#ifdef CONFIG_PMAC_PBOOKstatic void pmu_pass_intr(unsigned char *data, int len);#endif#ifdef CONFIG_ADBstruct adb_driver via_pmu_driver = {	"PMU",	pmu_probe,	pmu_init,	pmu_send_request,	pmu_adb_autopoll,	pmu_poll,	pmu_adb_reset_bus};#endif /* CONFIG_ADB */extern void low_sleep_handler(void);extern void sleep_save_intrs(int);extern void sleep_restore_intrs(void);extern int grackle_pcibios_read_config_word(unsigned char bus,	unsigned char dev_fn, unsigned char offset, unsigned short *val);extern int grackle_pcibios_write_config_word(unsigned char bus,	unsigned char dev_fn, unsigned char offset, unsigned short val);/* * This table indicates for each PMU opcode: * - the number of data bytes to be sent with the command, or -1 *   if a length byte should be sent, * - the number of response bytes which the PMU will return, or *   -1 if it will send a length byte. */static const s8 pmu_data_len[256][2] __openfirmwaredata = {/*	   0	   1	   2	   3	   4	   5	   6	   7  *//*00*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*08*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*10*/	{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*18*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},/*20*/	{-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},/*28*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},/*30*/	{ 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*38*/	{ 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},/*40*/	{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*48*/	{ 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},/*50*/	{ 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},/*58*/	{ 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},/*60*/	{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*68*/	{ 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},/*70*/	{ 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*78*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},/*80*/	{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*88*/	{ 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*90*/	{ 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*98*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*a0*/	{ 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},/*a8*/	{ 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*b0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*b8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*c0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*c8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},/*d0*/	{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*d8*/	{ 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},/*e0*/	{-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},/*e8*/	{ 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},/*f0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},/*f8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},};static char *pbook_type[] = {	"Unknown PowerBook",	"PowerBook 2400/3400/3500(G3)",	"PowerBook G3 Series",	"1999 PowerBook G3",	"Core99"};#ifdef CONFIG_PMAC_BACKLIGHTstatic struct backlight_controller pmu_backlight_controller = {	pmu_set_backlight_enable,	pmu_set_backlight_level};#endif /* CONFIG_PMAC_BACKLIGHT */int __openfirmwarefind_via_pmu(){	if (via != 0)		return 1;	vias = find_devices("via-pmu");	if (vias == 0)		return 0;	if (vias->next != 0)		printk(KERN_WARNING "Warning: only using 1st via-pmu\n");	if (vias->n_addrs < 1 || vias->n_intrs < 1) {		printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",		       vias->n_addrs, vias->n_intrs);		if (vias->n_addrs < 1 || vias->n_intrs < 1)			return 0;	}	spin_lock_init(&pmu_lock);	pmu_has_adb = 1;	if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)	    || device_is_compatible(vias->parent, "ohare")))		pmu_kind = PMU_OHARE_BASED;	else if (device_is_compatible(vias->parent, "paddington"))		pmu_kind = PMU_PADDINGTON_BASED;	else if (device_is_compatible(vias->parent, "heathrow"))		pmu_kind = PMU_HEATHROW_BASED;	else if (device_is_compatible(vias->parent, "Keylargo")) {		struct device_node *gpio, *gpiop;		pmu_kind = PMU_KEYLARGO_BASED;		pmu_has_adb = (find_type_devices("adb") != NULL);		gpiop = find_devices("gpio");		if (gpiop && gpiop->n_addrs) {			gpio_reg = ioremap(gpiop->addrs->address, 0x10);			gpio = find_devices("extint-gpio1");			if (gpio && gpio->parent == gpiop && gpio->n_intrs)				gpio_irq = gpio->intrs[0].line;		}	} else		pmu_kind = PMU_UNKNOWN;	via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);	out_8(&via[IER], IER_CLR | 0x7f);	/* disable all intrs */	out_8(&via[IFR], 0x7f);			/* clear IFR */	pmu_state = idle;	if (!init_pmu()) {		via = NULL;		return 0;	}	printk(KERN_INFO "PMU driver initialized for %s\n",	       pbook_type[pmu_kind]);	       	sys_ctrler = SYS_CTRLER_PMU;		return 1;}#ifdef CONFIG_ADBstatic int __openfirmwarepmu_probe(){	return vias == NULL? -ENODEV: 0;}static int __openfirmwarepmu_init(void){	if (vias == NULL)		return -ENODEV;	return 0;}#endif /* CONFIG_ADB *//* * We can't wait until pmu_init gets called, that happens too late. * It happens after IDE and SCSI initialization, which can take a few * seconds, and by that time the PMU could have given up on us and * turned us off. * This is called from arch/ppc/kernel/pmac_setup.c:pmac_init2(). */int via_pmu_start(void){	if (vias == NULL)		return -ENODEV;	bright_req_1.complete = 1;	bright_req_2.complete = 1;	bright_req_3.complete = 1;	if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",			(void *)0)) {		printk(KERN_ERR "VIA-PMU: can't get irq %d\n",		       vias->intrs[0].line);		return -EAGAIN;	}	if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) {		if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1/ADB", (void *)0))			printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq);	}	/* Enable interrupts */	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);	pmu_fully_inited = 1;#ifdef CONFIG_PMAC_BACKLIGHT	/* Enable backlight */	register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");#endif /* CONFIG_PMAC_BACKLIGHT */	/* Make sure PMU settle down before continuing. This is _very_ important	 * since the IDE probe may shut interrupts down for quite a bit of time. If	 * a PMU communication is pending while this happens, the PMU may timeout	 * Not that on Core99 machines, the PMU keeps sending us environement	 * messages, we should find a way to either fix IDE or make it call	 * pmu_suspend() before masking interrupts. This can also happens while	 * scolling with some fbdevs.	 */	do {		pmu_poll();	} while (pmu_state != idle);	return 0;}static int __openfirmwareinit_pmu(){	int timeout;	struct adb_request req;	out_8(&via[B], via[B] | TREQ);			/* negate TREQ */	out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK);	/* TACK in, TREQ out */	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);	timeout =  100000;	while (!req.complete) {		if (--timeout < 0) {			printk(KERN_ERR "init_pmu: no response from PMU\n");			return 0;		}		udelay(10);		pmu_poll();	}	/* ack all pending interrupts */	timeout = 100000;	interrupt_data[0] = 1;	while (interrupt_data[0] || pmu_state != idle) {		if (--timeout < 0) {			printk(KERN_ERR "init_pmu: timed out acking intrs\n");			return 0;		}		if (pmu_state == idle)			adb_int_pending = 1;		via_pmu_interrupt(0, 0, 0);		udelay(10);	}	/* Tell PMU we are ready. Which PMU support this ? */	if (pmu_kind == PMU_KEYLARGO_BASED) {		pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);		while (!req.complete)			pmu_poll();	}			return 1;}intpmu_get_model(void){	return pmu_kind;}#ifdef CONFIG_ADB/* Send an ADB command */static int __openfirmwarepmu_send_request(struct adb_request *req, int sync){	int i, ret;	if ((vias == NULL) || (!pmu_fully_inited)) {		req->complete = 1;		return -ENXIO;	}	ret = -EINVAL;	switch (req->data[0]) {	case PMU_PACKET:		for (i = 0; i < req->nbytes - 1; ++i)			req->data[i] = req->data[i+1];		--req->nbytes;		if (pmu_data_len[req->data[0]][1] != 0) {			req->reply[0] = ADB_RET_OK;			req->reply_len = 1;		} else			req->reply_len = 0;		ret = pmu_queue_request(req);		break;	case CUDA_PACKET:		switch (req->data[1]) {		case CUDA_GET_TIME:			if (req->nbytes != 2)				break;			req->data[0] = PMU_READ_RTC;			req->nbytes = 1;			req->reply_len = 3;			req->reply[0] = CUDA_PACKET;			req->reply[1] = 0;			req->reply[2] = CUDA_GET_TIME;			ret = pmu_queue_request(req);			break;		case CUDA_SET_TIME:			if (req->nbytes != 6)				break;			req->data[0] = PMU_SET_RTC;			req->nbytes = 5;			for (i = 1; i <= 4; ++i)				req->data[i] = req->data[i+1];			req->reply_len = 3;			req->reply[0] = CUDA_PACKET;			req->reply[1] = 0;			req->reply[2] = CUDA_SET_TIME;			ret = pmu_queue_request(req);			break;		}		break;	case ADB_PACKET:	    	if (!pmu_has_adb)    			return -ENXIO;		for (i = req->nbytes - 1; i > 1; --i)			req->data[i+2] = req->data[i];		req->data[3] = req->nbytes - 2;		req->data[2] = pmu_adb_flags;		/*req->data[1] = req->data[1];*/		req->data[0] = PMU_ADB_CMD;		req->nbytes += 2;		req->reply_expected = 1;		req->reply_len = 0;		ret = pmu_queue_request(req);		break;	}	if (ret) {		req->complete = 1;		return ret;	}	if (sync)

⌨️ 快捷键说明

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