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

📄 via-pmu68k.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
static void pmu_start(){	unsigned long flags;	struct adb_request *req;	/* assert pmu_state == idle */	/* get the packet to send */	save_flags(flags); cli();	req = current_req;	if (req == 0 || pmu_state != idle	    || (req->reply_expected && req_awaiting_reply))		goto out;	pmu_state = sending;	data_index = 1;	data_len = pmu_data_len[req->data[0]][0];	/* set the shift register to shift out and send a byte */	send_byte(req->data[0]);out:	restore_flags(flags);}void pmu_poll(){	unsigned long cpu_flags;	save_flags(cpu_flags);	cli();	if (via1[IFR] & SR_INT) {		via1[IFR] = SR_INT;		pmu_interrupt(IRQ_MAC_ADB_SR, NULL, NULL);	}	if (via1[IFR] & CB1_INT) {		via1[IFR] = CB1_INT;		pmu_interrupt(IRQ_MAC_ADB_CL, NULL, NULL);	}	restore_flags(cpu_flags);}static void pmu_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct adb_request *req;	int timeout, bite = 0;	/* to prevent compiler warning */#if 0	printk("pmu_interrupt: irq %d state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n",		irq, pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending);#endif	if (irq == IRQ_MAC_ADB_CL) {		/* CB1 interrupt */		adb_int_pending = 1;	} else if (irq == IRQ_MAC_ADB_SR) {	/* SR interrupt  */		if (via2[B] & TACK) {			printk(KERN_DEBUG "PMU: SR_INT but ack still high! (%x)\n", via2[B]);		}		/* if reading grab the byte */		if ((via1[ACR] & SR_OUT) == 0) bite = via1[SR];		/* reset TREQ and wait for TACK to go high */		via2[B] |= TREQ;		timeout = 3200;		while (!(via2[B] & TACK)) {			if (--timeout < 0) {				printk(KERN_ERR "PMU not responding (!ack)\n");				goto finish;			}			udelay(10);		}		switch (pmu_state) {		case sending:			req = current_req;			if (data_len < 0) {				data_len = req->nbytes - 1;				send_byte(data_len);				break;			}			if (data_index <= data_len) {				send_byte(req->data[data_index++]);				break;			}			req->sent = 1;			data_len = pmu_data_len[req->data[0]][1];			if (data_len == 0) {				pmu_state = idle;				current_req = req->next;				if (req->reply_expected)					req_awaiting_reply = req;				else					pmu_done(req);			} else {				pmu_state = reading;				data_index = 0;				reply_ptr = req->reply + req->reply_len;				recv_byte();			}			break;		case intack:			data_index = 0;			data_len = -1;			pmu_state = reading_intr;			reply_ptr = interrupt_data;			recv_byte();			break;		case reading:		case reading_intr:			if (data_len == -1) {				data_len = bite;				if (bite > 32)					printk(KERN_ERR "PMU: bad reply len %d\n",					       bite);			} else {				reply_ptr[data_index++] = bite;			}			if (data_index < data_len) {				recv_byte();				break;			}			if (pmu_state == reading_intr) {				pmu_handle_data(interrupt_data, data_index, regs);			} else {				req = current_req;				current_req = req->next;				req->reply_len += data_index;				pmu_done(req);			}			pmu_state = idle;			break;		default:			printk(KERN_ERR "pmu_interrupt: unknown state %d?\n",			       pmu_state);		}	}finish:	if (pmu_state == idle) {		if (adb_int_pending) {			pmu_state = intack;			send_byte(PMU_INT_ACK);			adb_int_pending = 0;		} else if (current_req) {			pmu_start();		}	}#if 0	printk("pmu_interrupt: exit state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n",		pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending);#endif}static void pmu_done(struct adb_request *req){	req->complete = 1;	if (req->done)		(*req->done)(req);}/* Interrupt data could be the result data from an ADB cmd */static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs){	static int show_pmu_ints = 1;	asleep = 0;	if (len < 1) {		adb_int_pending = 0;		return;	}	if (data[0] & PMU_INT_ADB) {		if ((data[0] & PMU_INT_ADB_AUTO) == 0) {			struct adb_request *req = req_awaiting_reply;			if (req == 0) {				printk(KERN_ERR "PMU: extra ADB reply\n");				return;			}			req_awaiting_reply = 0;			if (len <= 2)				req->reply_len = 0;			else {				memcpy(req->reply, data + 1, len - 1);				req->reply_len = len - 1;			}			pmu_done(req);		} else {			adb_input(data+1, len-1, regs, 1);		}	} else {		if (data[0] == 0x08 && len == 3) {			/* sound/brightness buttons pressed */			pmu_set_brightness(data[1] >> 3);			set_volume(data[2]);		} else if (show_pmu_ints			   && !(data[0] == PMU_INT_TICK && len == 1)) {			int i;			printk(KERN_DEBUG "pmu intr");			for (i = 0; i < len; ++i)				printk(" %.2x", data[i]);			printk("\n");		}	}}int backlight_level = -1;int backlight_enabled = 0;#define LEVEL_TO_BRIGHT(lev)	((lev) < 1? 0x7f: 0x4a - ((lev) << 1))void pmu_enable_backlight(int on){	struct adb_request req;	if (on) {	    /* first call: get current backlight value */	    if (backlight_level < 0) {		switch(pmu_kind) {		    case PMU_68K_V1:		    case PMU_68K_V2:			pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);			while (!req.complete)				pmu_poll();			printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]);			backlight_level = req.reply[1];			break;		    default:		        backlight_enabled = 0;		        return;		}	    }	    pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,	    	LEVEL_TO_BRIGHT(backlight_level));	    while (!req.complete)		pmu_poll();	}	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,	    PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));	while (!req.complete)		pmu_poll();	backlight_enabled = on;}void pmu_set_brightness(int level){	int bright;	backlight_level = level;	bright = LEVEL_TO_BRIGHT(level);	if (!backlight_enabled)		return;	if (bright_req_1.complete)		pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,		    bright);	if (bright_req_2.complete)		pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL,		    PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF));}void pmu_enable_irled(int on){	struct adb_request req;	pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |	    (on ? PMU_POW_ON : PMU_POW_OFF));	while (!req.complete)		pmu_poll();}static void set_volume(int level){}intpmu_present(void){	return (pmu_kind != PMU_UNKNOWN);}#if 0 /* needs some work for 68K *//* * This struct is used to store config register values for * PCI devices which may get powered off when we sleep. */static struct pci_save {	u16	command;	u16	cache_lat;	u16	intr;} *pbook_pci_saves;static int n_pbook_pci_saves;static inline void __openfirmwarepbook_pci_save(void){	int npci;	struct pci_dev *pd;	struct pci_save *ps;	npci = 0;	for (pd = pci_devices; pd != NULL; pd = pd->next)		++npci;	n_pbook_pci_saves = npci;	if (npci == 0)		return;	ps = (struct pci_save *) kmalloc(npci * sizeof(*ps), GFP_KERNEL);	pbook_pci_saves = ps;	if (ps == NULL)		return;	for (pd = pci_devices; pd != NULL && npci != 0; pd = pd->next) {		pci_read_config_word(pd, PCI_COMMAND, &ps->command);		pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);		pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);		++ps;		--npci;	}}static inline void __openfirmwarepbook_pci_restore(void){	u16 cmd;	struct pci_save *ps = pbook_pci_saves;	struct pci_dev *pd;	int j;	for (pd = pci_devices; pd != NULL; pd = pd->next, ++ps) {		if (ps->command == 0)			continue;		pci_read_config_word(pd, PCI_COMMAND, &cmd);		if ((ps->command & ~cmd) == 0)			continue;		switch (pd->hdr_type) {		case PCI_HEADER_TYPE_NORMAL:			for (j = 0; j < 6; ++j)				pci_write_config_dword(pd,					PCI_BASE_ADDRESS_0 + j*4,					pd->resource[j].start);			pci_write_config_dword(pd, PCI_ROM_ADDRESS,			       pd->resource[PCI_ROM_RESOURCE].start);			pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,				ps->cache_lat);			pci_write_config_word(pd, PCI_INTERRUPT_LINE,				ps->intr);			pci_write_config_word(pd, PCI_COMMAND, ps->command);			break;			/* other header types not restored at present */		}	}}/* * Put the powerbook to sleep. */#define IRQ_ENABLE	((unsigned int *)0xf3000024)#define MEM_CTRL	((unsigned int *)0xf8000070)int __openfirmware powerbook_sleep(void){	int ret, i, x;	static int save_backlight;	static unsigned int save_irqen;	unsigned long msr;	unsigned int hid0;	unsigned long p, wait;	struct adb_request sleep_req;	/* Notify device drivers */	ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL);	if (ret & NOTIFY_STOP_MASK)		return -EBUSY;	/* Sync the disks. */	/* XXX It would be nice to have some way to ensure that	 * nobody is dirtying any new buffers while we wait. */	fsync_dev(0);	/* Turn off the display backlight */	save_backlight = backlight_enabled;	if (save_backlight)		pmu_enable_backlight(0);	/* Give the disks a little time to actually finish writing */	for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )		mb();	/* Disable all interrupts except pmu */	save_irqen = in_le32(IRQ_ENABLE);	for (i = 0; i < 32; ++i)		if (i != vias->intrs[0].line && (save_irqen & (1 << i)))			disable_irq(i);	asm volatile("mtdec %0" : : "r" (0x7fffffff));	/* Save the state of PCI config space for some slots */	pbook_pci_save();	/* Set the memory controller to keep the memory refreshed	   while we're asleep */	for (i = 0x403f; i >= 0x4000; --i) {		out_be32(MEM_CTRL, i);		do {			x = (in_be32(MEM_CTRL) >> 16) & 0x3ff;		} while (x == 0);		if (x >= 0x100)			break;	}	/* Ask the PMU to put us to sleep */	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');	while (!sleep_req.complete)		mb();	/* displacement-flush the L2 cache - necessary? */	for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)		i = *(volatile int *)p;	asleep = 1;	/* Put the CPU into sleep mode */	asm volatile("mfspr %0,1008" : "=r" (hid0) :);	hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;	asm volatile("mtspr 1008,%0" : : "r" (hid0));	save_flags(msr);	msr |= MSR_POW | MSR_EE;	restore_flags(msr);	udelay(10);	/* OK, we're awake again, start restoring things */	out_be32(MEM_CTRL, 0x3f);	pbook_pci_restore();	/* wait for the PMU interrupt sequence to complete */	while (asleep)		mb();	/* reenable interrupts */	for (i = 0; i < 32; ++i)		if (i != vias->intrs[0].line && (save_irqen & (1 << i)))			enable_irq(i);	/* Notify drivers */	notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);	/* reenable ADB autopoll */	pmu_adb_autopoll(adb_dev_map);	/* Turn on the screen backlight, if it was on before */	if (save_backlight)		pmu_enable_backlight(1);	/* Wait for the hard disk to spin up */	return 0;}/* * Support for /dev/pmu device */static int __openfirmware pmu_open(struct inode *inode, struct file *file){	return 0;}static ssize_t __openfirmware pmu_read(struct file *file, char *buf,			size_t count, loff_t *ppos){	return 0;}static ssize_t __openfirmware pmu_write(struct file *file, const char *buf,			 size_t count, loff_t *ppos){	return 0;}/* Note: removed __openfirmware here since it causes link errors */static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp,		     u_int cmd, u_long arg){	int error;	__u32 value;	switch (cmd) {	    case PMU_IOC_SLEEP:	    	return -ENOSYS;	    case PMU_IOC_GET_BACKLIGHT:		return put_user(backlight_level, (__u32 *)arg);	    case PMU_IOC_SET_BACKLIGHT:		error = get_user(value, (__u32 *)arg);		if (!error)			pmu_set_brightness(value);		return error;	    case PMU_IOC_GET_MODEL:	    	return put_user(pmu_kind, (__u32 *)arg);	}	return -EINVAL;}static struct file_operations pmu_device_fops = {	read:		pmu_read,	write:		pmu_write,	ioctl:		pmu_ioctl,	open:		pmu_open,};static struct miscdevice pmu_device = {	PMU_MINOR, "pmu", &pmu_device_fops};void pmu_device_init(void){	if (via)		misc_register(&pmu_device);}#endif /* CONFIG_PMAC_PBOOK */

⌨️ 快捷键说明

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