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

📄 hp_sdc.c

📁 QQ2440板子
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	if (curr->idx >= curr->endidx) { /* This transaction is over. */		if (act & HP_SDC_ACT_DEALLOC) kfree(curr);		hp_sdc.tq[curridx] = NULL;	}	else {		curr->actidx = idx + 1;		curr->idx = idx + 2;	}	/* Interleave outbound data between the transactions. */	hp_sdc.wcurr++;	if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; finish:	/* If by some quirk IBF has cleared and our ISR has run to 	   see that that has happened, do it all again. */	if (!hp_sdc.ibf && limit++ < 20) goto anew; done:	if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task);	write_unlock(&hp_sdc.lock);	return 0;}/******* Functions called in either user or kernel context ****/int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {	unsigned long flags;	int i;	if (this == NULL) {		tasklet_schedule(&hp_sdc.task);		return -EINVAL;	};	write_lock_irqsave(&hp_sdc.lock, flags);	/* Can't have same transaction on queue twice */	for (i=0; i < HP_SDC_QUEUE_LEN; i++)		if (hp_sdc.tq[i] == this) goto fail;	this->actidx = 0;	this->idx = 1;	/* Search for empty slot */	for (i=0; i < HP_SDC_QUEUE_LEN; i++) {		if (hp_sdc.tq[i] == NULL) {			hp_sdc.tq[i] = this;			write_unlock_irqrestore(&hp_sdc.lock, flags);			tasklet_schedule(&hp_sdc.task);			return 0;		}	}	write_unlock_irqrestore(&hp_sdc.lock, flags);	printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");	return -EBUSY; fail:	write_unlock_irqrestore(&hp_sdc.lock,flags);	printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");	return -EINVAL;}int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {	unsigned long flags;	int i;	write_lock_irqsave(&hp_sdc.lock, flags);	/* TODO: don't remove it if it's not done. */	for (i=0; i < HP_SDC_QUEUE_LEN; i++)		if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL;	write_unlock_irqrestore(&hp_sdc.lock, flags);	return 0;}/********************** User context functions **************************/int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {	if (callback == NULL || hp_sdc.dev == NULL) {		return -EINVAL;	}	write_lock_irq(&hp_sdc.hook_lock);	if (hp_sdc.timer != NULL) {		write_unlock_irq(&hp_sdc.hook_lock);		return -EBUSY;	}	hp_sdc.timer = callback;	/* Enable interrupts from the timers */	hp_sdc.im &= ~HP_SDC_IM_FH;        hp_sdc.im &= ~HP_SDC_IM_PT;	hp_sdc.im &= ~HP_SDC_IM_TIMERS;	hp_sdc.set_im = 1;	write_unlock_irq(&hp_sdc.hook_lock);	tasklet_schedule(&hp_sdc.task);	return 0;}int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {	if (callback == NULL || hp_sdc.dev == NULL) {		return -EINVAL;	}	write_lock_irq(&hp_sdc.hook_lock);	if (hp_sdc.hil != NULL) {		write_unlock_irq(&hp_sdc.hook_lock);		return -EBUSY;	}	hp_sdc.hil = callback;	hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);	hp_sdc.set_im = 1;	write_unlock_irq(&hp_sdc.hook_lock);	tasklet_schedule(&hp_sdc.task);	return 0;}int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {	if (callback == NULL || hp_sdc.dev == NULL) {		return -EINVAL;	}	write_lock_irq(&hp_sdc.hook_lock);	if (hp_sdc.cooked != NULL) {		write_unlock_irq(&hp_sdc.hook_lock);		return -EBUSY;	}	/* Enable interrupts from the HIL MLC */	hp_sdc.cooked = callback;	hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);	hp_sdc.set_im = 1;	write_unlock_irq(&hp_sdc.hook_lock);	tasklet_schedule(&hp_sdc.task);	return 0;}int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) {	write_lock_irq(&hp_sdc.hook_lock);	if ((callback != hp_sdc.timer) ||	    (hp_sdc.timer == NULL)) {		write_unlock_irq(&hp_sdc.hook_lock);		return -EINVAL;	}	/* Disable interrupts from the timers */	hp_sdc.timer = NULL;	hp_sdc.im |= HP_SDC_IM_TIMERS;	hp_sdc.im |= HP_SDC_IM_FH;	hp_sdc.im |= HP_SDC_IM_PT;	hp_sdc.set_im = 1;	write_unlock_irq(&hp_sdc.hook_lock);	tasklet_schedule(&hp_sdc.task);	return 0;}int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) {	write_lock_irq(&hp_sdc.hook_lock);	if ((callback != hp_sdc.hil) ||	    (hp_sdc.hil == NULL)) {		write_unlock_irq(&hp_sdc.hook_lock);		return -EINVAL;	}	hp_sdc.hil = NULL;	/* Disable interrupts from HIL only if there is no cooked driver. */	if(hp_sdc.cooked == NULL) {		hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET);		hp_sdc.set_im = 1;	}	write_unlock_irq(&hp_sdc.hook_lock);	tasklet_schedule(&hp_sdc.task);	return 0;}int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) {	write_lock_irq(&hp_sdc.hook_lock);	if ((callback != hp_sdc.cooked) ||	    (hp_sdc.cooked == NULL)) {		write_unlock_irq(&hp_sdc.hook_lock);		return -EINVAL;	}	hp_sdc.cooked = NULL;	/* Disable interrupts from HIL only if there is no raw HIL driver. */	if(hp_sdc.hil == NULL) {		hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET);		hp_sdc.set_im = 1;	}	write_unlock_irq(&hp_sdc.hook_lock);	tasklet_schedule(&hp_sdc.task);	return 0;}/************************* Keepalive timer task *********************/void hp_sdc_kicker (unsigned long data) {	tasklet_schedule(&hp_sdc.task);	/* Re-insert the periodic task. */	mod_timer(&hp_sdc.kicker, jiffies + HZ);}/************************** Module Initialization ***************************/#if defined(__hppa__)static struct parisc_device_id hp_sdc_tbl[] = {	{		.hw_type =	HPHW_FIO, 		.hversion_rev =	HVERSION_REV_ANY_ID,		.hversion =	HVERSION_ANY_ID,		.sversion =	0x73, 	 },	{ 0, }};MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl);static int __init hp_sdc_init_hppa(struct parisc_device *d);static struct parisc_driver hp_sdc_driver = {	.name =		"HP SDC",	.id_table =	hp_sdc_tbl,	.probe =	hp_sdc_init_hppa,};#endif /* __hppa__ */static int __init hp_sdc_init(void){	int i;	char *errstr;	hp_sdc_transaction t_sync;	uint8_t ts_sync[6];	struct semaphore s_sync;  	rwlock_init(&hp_sdc.lock);  	rwlock_init(&hp_sdc.ibf_lock);  	rwlock_init(&hp_sdc.rtq_lock);  	rwlock_init(&hp_sdc.hook_lock);	hp_sdc.timer		= NULL;	hp_sdc.hil		= NULL;	hp_sdc.pup		= NULL;	hp_sdc.cooked		= NULL;	hp_sdc.im		= HP_SDC_IM_MASK;  /* Mask maskable irqs */	hp_sdc.set_im		= 1;	hp_sdc.wi		= 0xff;	hp_sdc.r7[0]		= 0xff;	hp_sdc.r7[1]		= 0xff;	hp_sdc.r7[2]		= 0xff;	hp_sdc.r7[3]		= 0xff;	hp_sdc.ibf		= 1;	for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL;	hp_sdc.wcurr		= -1;        hp_sdc.rcurr		= -1;	hp_sdc.rqty		= 0;	hp_sdc.dev_err = -ENODEV;	errstr = "IO not found for";	if (!hp_sdc.base_io) goto err0;	errstr = "IRQ not found for";	if (!hp_sdc.irq) goto err0;	hp_sdc.dev_err = -EBUSY;#if defined(__hppa__)	errstr = "IO not available for";        if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0;#endif		errstr = "IRQ not available for";        if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC",		       (void *) hp_sdc.base_io)) goto err1;	errstr = "NMI not available for";	if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI", 			(void *) hp_sdc.base_io)) goto err2;	printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", 	       (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);	hp_sdc_status_in8();	hp_sdc_data_in8();	tasklet_init(&hp_sdc.task, hp_sdc_tasklet, 0);	/* Sync the output buffer registers, thus scheduling hp_sdc_tasklet. */	t_sync.actidx	= 0;	t_sync.idx	= 1;	t_sync.endidx	= 6;	t_sync.seq	= ts_sync;	ts_sync[0]	= HP_SDC_ACT_DATAREG | HP_SDC_ACT_SEMAPHORE;	ts_sync[1]	= 0x0f;	ts_sync[2] = ts_sync[3]	= ts_sync[4] = ts_sync[5] = 0;	t_sync.act.semaphore = &s_sync;	init_MUTEX_LOCKED(&s_sync);	hp_sdc_enqueue_transaction(&t_sync);	down(&s_sync); /* Wait for t_sync to complete */	/* Create the keepalive task */	init_timer(&hp_sdc.kicker);	hp_sdc.kicker.expires = jiffies + HZ;	hp_sdc.kicker.function = &hp_sdc_kicker;	add_timer(&hp_sdc.kicker);	hp_sdc.dev_err = 0;	return 0; err2:	free_irq(hp_sdc.irq, NULL); err1:	release_region(hp_sdc.data_io, 2); err0:	printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n", 		errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);	hp_sdc.dev = NULL;	return hp_sdc.dev_err;}#if defined(__hppa__)static int __init hp_sdc_init_hppa(struct parisc_device *d){	if (!d) return 1;	if (hp_sdc.dev != NULL) return 1;	/* We only expect one SDC */	hp_sdc.dev		= d;	hp_sdc.irq		= d->irq;	hp_sdc.nmi		= d->aux_irq;	hp_sdc.base_io		= d->hpa;	hp_sdc.data_io		= d->hpa + 0x800;	hp_sdc.status_io	= d->hpa + 0x801;	return hp_sdc_init();}#endif /* __hppa__ */#if !defined(__mc68000__) /* Link error on m68k! */static void __exit hp_sdc_exit(void)#elsestatic void hp_sdc_exit(void)#endif{	write_lock_irq(&hp_sdc.lock);	/* Turn off all maskable "sub-function" irq's. */	hp_sdc_spin_ibf();	sdc_writeb(HP_SDC_CMD_SET_IM | HP_SDC_IM_MASK, hp_sdc.status_io);	/* Wait until we know this has been processed by the i8042 */	hp_sdc_spin_ibf();	free_irq(hp_sdc.nmi, NULL);	free_irq(hp_sdc.irq, NULL);	write_unlock_irq(&hp_sdc.lock);	del_timer(&hp_sdc.kicker);	tasklet_kill(&hp_sdc.task);/*        release_region(hp_sdc.data_io, 2); */#if defined(__hppa__)	if (unregister_parisc_driver(&hp_sdc_driver)) 		printk(KERN_WARNING PREFIX "Error unregistering HP SDC");#endif}static int __init hp_sdc_register(void){	hp_sdc_transaction tq_init;	uint8_t tq_init_seq[5];	struct semaphore tq_init_sem;#if defined(__mc68000__)	mm_segment_t fs;	unsigned char i;#endif		hp_sdc.dev = NULL;	hp_sdc.dev_err = 0;#if defined(__hppa__)	if (register_parisc_driver(&hp_sdc_driver)) {		printk(KERN_WARNING PREFIX "Error registering SDC with system bus tree.\n");		return -ENODEV;	}#elif defined(__mc68000__)	if (!MACH_IS_HP300)	    return -ENODEV;	hp_sdc.irq	 = 1;	hp_sdc.nmi	 = 7;	hp_sdc.base_io	 = (unsigned long) 0xf0428000;	hp_sdc.data_io	 = (unsigned long) hp_sdc.base_io + 1;	hp_sdc.status_io = (unsigned long) hp_sdc.base_io + 3;	fs = get_fs();	set_fs(KERNEL_DS);	if (!get_user(i, (unsigned char *)hp_sdc.data_io))		hp_sdc.dev = (void *)1;	set_fs(fs);	hp_sdc.dev_err   = hp_sdc_init();#endif	if (hp_sdc.dev == NULL) {		printk(KERN_WARNING PREFIX "No SDC found.\n");		return hp_sdc.dev_err;	}	init_MUTEX_LOCKED(&tq_init_sem);	tq_init.actidx		= 0;	tq_init.idx		= 1;	tq_init.endidx		= 5;	tq_init.seq		= tq_init_seq;	tq_init.act.semaphore	= &tq_init_sem;	tq_init_seq[0] = 	  HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;	tq_init_seq[1] = HP_SDC_CMD_READ_KCC;	tq_init_seq[2] = 1;	tq_init_seq[3] = 0;	tq_init_seq[4] = 0;	hp_sdc_enqueue_transaction(&tq_init);	down(&tq_init_sem);	up(&tq_init_sem);	if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {		printk(KERN_WARNING PREFIX "Error reading config byte.\n");		hp_sdc_exit();		return -ENODEV;	}	hp_sdc.r11 = tq_init_seq[4];	if (hp_sdc.r11 & HP_SDC_CFG_NEW) {		char *str;		printk(KERN_INFO PREFIX "New style SDC\n");		tq_init_seq[1] = HP_SDC_CMD_READ_XTD;		tq_init.actidx		= 0;		tq_init.idx		= 1;		down(&tq_init_sem);		hp_sdc_enqueue_transaction(&tq_init);				down(&tq_init_sem);		up(&tq_init_sem);		if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {			printk(KERN_WARNING PREFIX "Error reading extended config byte.\n");			return -ENODEV;		}		hp_sdc.r7e = tq_init_seq[4];		HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str)		printk(KERN_INFO PREFIX "Revision: %s\n", str);		if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) {			printk(KERN_INFO PREFIX "TI SN76494 beeper present\n");		}		if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) {			printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n");		}		printk(KERN_INFO PREFIX "Spunking the self test register to force PUP "		       "on next firmware reset.\n");		tq_init_seq[0] = HP_SDC_ACT_PRECMD | 			HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;		tq_init_seq[1] = HP_SDC_CMD_SET_STR;		tq_init_seq[2] = 1;		tq_init_seq[3] = 0;		tq_init.actidx		= 0;		tq_init.idx		= 1;		tq_init.endidx		= 4;		down(&tq_init_sem);		hp_sdc_enqueue_transaction(&tq_init);				down(&tq_init_sem);		up(&tq_init_sem);	}	else {		printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n", 		       (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");	}        return 0;}module_init(hp_sdc_register);module_exit(hp_sdc_exit);/* Timing notes:  These measurements taken on my 64MHz 7100-LC (715/64)  *                                              cycles cycles-adj    time * between two consecutive mfctl(16)'s:              4        n/a    63ns * hp_sdc_spin_ibf when idle:                      119        115   1.7us * gsc_writeb status register:                      83         79   1.2us * IBF to clear after sending SET_IM:             6204       6006    93us * IBF to clear after sending LOAD_RT:            4467       4352    68us   * IBF to clear after sending two LOAD_RTs:      18974      18859   295us * READ_T1, read status/data, IRQ, call handler: 35564        n/a   556us * cmd to ~IBF READ_T1 2nd time right after:   5158403        n/a    81ms * between IRQ received and ~IBF for above:    2578877        n/a    40ms * * Performance stats after a run of this module configuring HIL and * receiving a few mouse events: * * status in8  282508 cycles 7128 calls * status out8   8404 cycles  341 calls * data out8     1734 cycles   78 calls * isr         174324 cycles  617 calls (includes take) * take          1241 cycles    2 calls * put        1411504 cycles 6937 calls * task       1655209 cycles 6937 calls (includes put) * */

⌨️ 快捷键说明

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