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

📄 hd64465_ss.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	if (changed & SS_STSCHG) {	    if (state->csc_mask & SS_STSCHG)		cscier |= HD64465_PCCCSCIER_PSCE;	    else		cscier &= ~HD64465_PCCCSCIER_PSCE;	}    	hs_out(sp, cscier, CSCIER);	if (sp->state.io_irq && !state->io_irq)	    hs_unmap_irq(sp, sp->state.io_irq);	else if (!sp->state.io_irq && state->io_irq)	    hs_map_irq(sp, state->io_irq);    	/*	 * Handle changes in the flags field,	 * by propagating to config registers.	 */		changed = sp->state.flags ^ state->flags;	if (changed & SS_IOCARD) {	    DPRINTK("card type: %s\n",		    (state->flags & SS_IOCARD ? "i/o" : "memory" ));	    bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCT,		state->flags & SS_IOCARD);	}	if (changed & SS_RESET) {	    DPRINTK("%s reset card\n",		(state->flags & SS_RESET ? "start" : "stop"));	    bool_to_regbit(sp, GCR, HD64465_PCCGCR_PCCR,		state->flags & SS_RESET);	}	if (changed & SS_OUTPUT_ENA) {	    DPRINTK("%sabling card output\n",		(state->flags & SS_OUTPUT_ENA ? "en" : "dis"));	    bool_to_regbit(sp, GCR, HD64465_PCCGCR_PDRV,		state->flags & SS_OUTPUT_ENA);	}    	/* TODO: SS_SPKR_ENA */	    /*    	hd64465_io_debug = 0; */	sp->state = *state;	    	restore_flags(flags);#if HD64465_DEBUG > 10	if (state->flags & SS_OUTPUT_ENA)   	    cis_hex_dump((const unsigned char*)sp->mem_base, 0x100);#endif	return 0;}/*============================================================*/static int hs_get_io_map(unsigned int sock, struct pccard_io_map *io){    	hs_socket_t *sp = &hs_sockets[sock];	int map = io->map;    	DPRINTK("hs_get_io_map(%d, %d)\n", sock, map);	if (map >= MAX_IO_WIN)	    return -EINVAL;		*io = sp->io_maps[map];	return 0;}/*============================================================*/static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io){    	hs_socket_t *sp = &hs_sockets[sock];	int map = io->map;	struct pccard_io_map *sio;	pgprot_t prot;    	DPRINTK("hs_set_io_map(sock=%d, map=%d, flags=0x%x, speed=%dns, start=0x%04x, stop=0x%04x)\n",	    sock, map, io->flags, io->speed, io->start, io->stop);	if (map >= MAX_IO_WIN)	    return -EINVAL;	sio = &sp->io_maps[map];    	/* check for null changes */	    	if (io->flags == sio->flags &&	    io->start == sio->start &&	    io->stop == sio->stop)	    return 0;		if (io->flags & MAP_AUTOSZ)	    prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IODYN);	else if (io->flags & MAP_16BIT)	    prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO16);	else	    prot = PAGE_KERNEL_PCC(sock, _PAGE_PCC_IO8);	/* TODO: handle MAP_USE_WAIT */	if (io->flags & MAP_USE_WAIT)	    printk(KERN_INFO MODNAME ": MAP_USE_WAIT unimplemented\n");	/* TODO: handle MAP_PREFETCH */	if (io->flags & MAP_PREFETCH)	    printk(KERN_INFO MODNAME ": MAP_PREFETCH unimplemented\n");	/* TODO: handle MAP_WRPROT */	if (io->flags & MAP_WRPROT)	    printk(KERN_INFO MODNAME ": MAP_WRPROT unimplemented\n");	/* TODO: handle MAP_0WS */	if (io->flags & MAP_0WS)	    printk(KERN_INFO MODNAME ": MAP_0WS unimplemented\n");	if (io->flags & MAP_ACTIVE) {	    unsigned long pstart, psize, paddrbase, vaddrbase;	    	    paddrbase = virt_to_phys((void*)(sp->mem_base + 2 * HD64465_PCC_WINDOW));	    vaddrbase = (unsigned long)sp->io_vma->addr;	    pstart = io->start & PAGE_MASK;	    psize = ((io->stop + PAGE_SIZE) & PAGE_MASK) - pstart;    	    /*	     * Change PTEs in only that portion of the mapping requested	     * by the caller.  This means that most of the time, most of	     * the PTEs in the io_vma will be unmapped and only the bottom	     * page will be mapped.  But the code allows for weird cards	     * that might want IO ports > 4K.	     */	    DPRINTK("remap_page_range(vaddr=0x%08lx, paddr=0x%08lx, size=0x%08lxx)\n",	    	vaddrbase + pstart, paddrbase + pstart, psize);	    remap_page_range(vaddrbase + pstart, paddrbase + pstart, psize, prot);	    	    /*	     * Change the mapping used by inb() outb() etc	     */	    hd64465_port_map(	    	io->start,		io->stop - io->start + 1,	    	vaddrbase + io->start,0);	} else {	    hd64465_port_unmap(	    	sio->start,		sio->stop - sio->start + 1);	    /* TODO: remap_page_range() to mark pages not present ? */	}		*sio = *io;	return 0;}/*============================================================*/static int hs_get_mem_map(unsigned int sock, struct pccard_mem_map *mem){    	hs_socket_t *sp = &hs_sockets[sock];	int map = mem->map;    	DPRINTK("hs_get_mem_map(%d, %d)\n", sock, map);	if (map >= MAX_WIN)	    return -EINVAL;		*mem = sp->mem_maps[map];	return 0;}/*============================================================*/static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem){    	hs_socket_t *sp = &hs_sockets[sock];	struct pccard_mem_map *smem;	int map = mem->map;	unsigned long paddr, size;#if 0    	DPRINTK("hs_set_mem_map(sock=%d, map=%d, flags=0x%x, sys_start=0x%08lx, sys_end=0x%08lx, card_start=0x%08x)\n",	    sock, map, mem->flags, mem->sys_start, mem->sys_stop, mem->card_start);#endif	if (map >= MAX_WIN)	    return -EINVAL;	smem = &sp->mem_maps[map];		size = mem->sys_stop - mem->sys_start + 1;		paddr = sp->mem_base;	    	    /* base of Attribute mapping */	if (!(mem->flags & MAP_ATTRIB))	    paddr += HD64465_PCC_WINDOW;    /* base of Common mapping */	paddr += mem->card_start;    	/* Because we specified SS_CAP_STATIC_MAP, we are obliged	 * at this time to report the system address corresponding	 * to the card address requested.  This is how Socket Services	 * queries our fixed mapping.  I wish this fact had been	 * documented - Greg Banks.	 */    	mem->sys_start = paddr;	mem->sys_stop = paddr + size - 1;		*smem = *mem;	    	return 0;}/* TODO: do we need to use the MMU to access Common memory ??? *//*============================================================*/static void hs_proc_setup(unsigned int sock, struct proc_dir_entry *base){    	DPRINTK("hs_proc_setup(%d)\n", sock);}/*============================================================*//* * This function is registered with the HD64465 glue code to do a * secondary demux step on the PCMCIA interrupts.  It handles  * mapping the IREQ request from the card to a standard Linux * IRQ, as requested by SocketServices. */static int hs_irq_demux(int irq, void *dev){    	hs_socket_t *sp = (hs_socket_t *)dev;	u_int cscr;    	    	DPRINTK("hs_irq_demux(irq=%d)\n", irq);    	if (sp->state.io_irq &&	    (cscr = hs_in(sp, CSCR)) & HD64465_PCCCSCR_PIREQ) {	    cscr &= ~HD64465_PCCCSCR_PIREQ;	    hs_out(sp, cscr, CSCR);	    return sp->state.io_irq;	}	    	return irq;}/*============================================================*//* * Interrupt handling routine. * * This uses the schedule_task() technique to cause reportable events * such as card insertion and removal to be handled in keventd's * process context. */ static void hs_events_bh(void *dummy){	hs_socket_t *sp;	u_int events;	int i;	for (i=0; i<HS_MAX_SOCKETS; i++) {	    sp = &hs_sockets[i];	    spin_lock_irq(&hs_pending_event_lock);	    events = sp->pending_events;	    sp->pending_events = 0;	    spin_unlock_irq(&hs_pending_event_lock);	    	    if (sp->handler)		sp->handler(sp->handler_info, events);	}}static struct tq_struct hs_events_task = {	routine:	hs_events_bh};static void hs_interrupt(int irq, void *dev, struct pt_regs *regs){    	hs_socket_t *sp = (hs_socket_t *)dev;	u_int events = 0;	u_int cscr;			cscr = hs_in(sp, CSCR);		DPRINTK("hs_interrupt, cscr=%04x\n", cscr);	/* check for bus-related changes to be reported to Socket Services */	if (cscr & HD64465_PCCCSCR_PCDC) {	    /* double-check for a 16-bit card, as we don't support CardBus */	    if ((hs_in(sp, ISR) & HD64465_PCCISR_PCD_MASK) != 0) {	    	printk(KERN_NOTICE MODNAME		    ": socket %d, card not a supported card type or not inserted correctly\n",		    hs_sockno(sp));		/* Don't do the rest unless a card is present */		cscr &= ~(HD64465_PCCCSCR_PCDC|		    	  HD64465_PCCCSCR_PRC|			  HD64465_PCCCSCR_PBW|		    	  HD64465_PCCCSCR_PBD|			  HD64465_PCCCSCR_PSC);	    } else {	    	cscr &= ~HD64465_PCCCSCR_PCDC;		events |= SS_DETECT;    	/* card insertion or removal */    	    }	}	if (cscr & HD64465_PCCCSCR_PRC) {	    cscr &= ~HD64465_PCCCSCR_PRC;	    events |= SS_READY;     	/* ready signal changed */	}	if (cscr & HD64465_PCCCSCR_PBW) {	    cscr &= ~HD64465_PCCCSCR_PSC;	    events |= SS_BATWARN;     	/* battery warning */	}	if (cscr & HD64465_PCCCSCR_PBD) {	    cscr &= ~HD64465_PCCCSCR_PSC;	    events |= SS_BATDEAD;     	/* battery dead */	}	if (cscr & HD64465_PCCCSCR_PSC) {	    cscr &= ~HD64465_PCCCSCR_PSC;	    events |= SS_STSCHG;     	/* STSCHG (status changed) signal */	}		if (cscr & HD64465_PCCCSCR_PIREQ) {	    cscr &= ~HD64465_PCCCSCR_PIREQ;    	    /* This should have been dealt with during irq demux */	    	    printk(KERN_NOTICE MODNAME ": unexpected IREQ from card\n");	}	hs_out(sp, cscr, CSCR);	if (events) {	    /*    	     * Arrange for events to be reported to the registered	     * event handler function (from CardServices) in a process	     * context (keventd) "soon".	     */	    spin_lock(&hs_pending_event_lock);	    sp->pending_events |= events;	    spin_unlock(&hs_pending_event_lock);	    	    schedule_task(&hs_events_task);	}}/*============================================================*/static struct pccard_operations hs_operations = {	hs_init,	hs_suspend,	hs_register_callback,	hs_inquire_socket,	hs_get_status,	hs_get_socket,	hs_set_socket,	hs_get_io_map,	hs_set_io_map,	hs_get_mem_map,	hs_set_mem_map,	hs_proc_setup};static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,    	    unsigned int ctrl_base){    	unsigned short v;    	int i, err;    	memset(sp, 0, sizeof(*sp));	sp->irq = irq;	sp->mem_base = mem_base;	sp->mem_length = 4*HD64465_PCC_WINDOW;	/* 16MB */	sp->ctrl_base = ctrl_base;		for (i=0 ; i<MAX_IO_WIN ; i++)	    sp->io_maps[i].map = i;	for (i=0 ; i<MAX_WIN ; i++)	    sp->mem_maps[i].map = i;		if ((sp->io_vma = get_vm_area(HS_IO_MAP_SIZE, VM_IOREMAP)) == 0)	    return -ENOMEM;	hd64465_register_irq_demux(sp->irq, hs_irq_demux, sp);	    	if ((err = request_irq(sp->irq, hs_interrupt, SA_INTERRUPT, MODNAME, sp)) < 0)	    return err;    	if (request_mem_region(sp->mem_base, sp->mem_length, MODNAME) == 0) {    	    sp->mem_base = 0;	    return -ENOMEM;	}	/* According to section 3.2 of the PCMCIA standard, low-voltage	 * capable cards must implement cold insertion, i.e. Vpp and	 * Vcc set to 0 before card is inserted.	 */	/*hs_set_voltages(sp, 0, 0);*/		/* hi-Z the outputs to the card and set 16MB map mode */	v = hs_in(sp, GCR);	v &= ~HD64465_PCCGCR_PCCT;  	/* memory-only card */	hs_out(sp, v, GCR);	v = hs_in(sp, GCR);	v |= HD64465_PCCGCR_PDRV;   	/* enable outputs to card */	hs_out(sp, v, GCR);	v = hs_in(sp, GCR);	v |= HD64465_PCCGCR_PMMOD; 	/* 16MB mapping mode */	hs_out(sp, v, GCR);	v = hs_in(sp, GCR);	/* lowest 16MB of Common */	v &= ~(HD64465_PCCGCR_PPA25|HD64465_PCCGCR_PPA24); 	hs_out(sp, v, GCR);		hs_reset_socket(sp, 1);    	return 0;}static void hs_exit_socket(hs_socket_t *sp){    	unsigned short cscier, gcr;		/* turn off interrupts in hardware */    	cscier = hs_in(sp, CSCIER);	cscier = (cscier & IER_MASK) | IER_OFF;    	hs_out(sp, cscier, CSCIER);		/* hi-Z the outputs to the card */    	gcr = hs_in(sp, GCR);	gcr &= HD64465_PCCGCR_PDRV;	hs_out(sp, gcr, GCR);    	/* power the card down */	hs_set_voltages(sp, 0, 0);    	if (sp->mem_base != 0)	    release_mem_region(sp->mem_base, sp->mem_length);	if (sp->irq != 0) {	    free_irq(sp->irq, hs_interrupt);    	    hd64465_unregister_irq_demux(sp->irq);	}	if (sp->io_vma != 0)	    vfree(sp->io_vma->addr);}static int __init init_hs(void){	servinfo_t serv;	int i;	unsigned short v;    	/*	 * Check API version	 */	pcmcia_get_card_services_info(&serv);	if (serv.Revision != CS_RELEASE_CODE) {	    printk(KERN_NOTICE MODNAME ": Card Services release does not match!\n");	    return -ENODEV;	}/*	hd64465_io_debug = 1; */		/* Wake both sockets out of STANDBY mode */	/* TODO: wait 15ms */	v = inw(HD64465_REG_SMSCR);	v &= ~(HD64465_SMSCR_PC0ST|HD64465_SMSCR_PC1ST);	outw(v, HD64465_REG_SMSCR);	/* keep power controller out of shutdown mode */	v = inb(HD64465_REG_PCC0SCR);	v |= HD64465_PCCSCR_SHDN;	outb(v, HD64465_REG_PCC0SCR);    	/* use serial (TPS2206) power controller */	v = inb(HD64465_REG_PCC0CSCR);	v |= HD64465_PCCCSCR_PSWSEL;	outb(v, HD64465_REG_PCC0CSCR);    	hs_set_voltages(&hs_sockets[0], 0, 0);    	hs_set_voltages(&hs_sockets[1], 0, 0);		/*	 * Setup hs_sockets[] structures and request system resources.	 * TODO: on memory allocation failure, power down the socket	 *       before quitting.	 */	i = hs_init_socket(&hs_sockets[0],	    HD64465_IRQ_PCMCIA0,	    HD64465_PCC0_BASE,	    HD64465_REG_PCC0ISR);	if (i < 0)	    return i;	i = hs_init_socket(&hs_sockets[1],	    HD64465_IRQ_PCMCIA1,	    HD64465_PCC1_BASE,	    HD64465_REG_PCC1ISR);	if (i < 0)	    return i;/*	hd64465_io_debug = 0; */	    	if (register_ss_entry(HS_MAX_SOCKETS, &hs_operations) != 0) {	    for (i=0 ; i<HS_MAX_SOCKETS ; i++)		hs_exit_socket(&hs_sockets[i]);    	    return -ENODEV;	}	printk(KERN_INFO "HD64465 PCMCIA bridge:\n");	for (i=0 ; i<HS_MAX_SOCKETS ; i++) {	    hs_socket_t *sp = &hs_sockets[i];	    	    printk(KERN_INFO "  socket %d at 0x%08lx irq %d io window %ldK@0x%08lx\n",	    	i, sp->mem_base, sp->irq,		sp->io_vma->size>>10, (unsigned long)sp->io_vma->addr);	}    	return 0;}static void __exit exit_hs(void){    	u_long flags;	int i;		save_and_cli(flags);    	/*	 * Release kernel resources	 */	for (i=0 ; i<HS_MAX_SOCKETS ; i++)	    hs_exit_socket(&hs_sockets[i]);	unregister_ss_entry(&hs_operations);		restore_flags(flags);}module_init(init_hs);module_exit(exit_hs);/*============================================================*//*END*/

⌨️ 快捷键说明

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