📄 m8xx_pcmcia.c
字号:
M8XX_PCMCIA_MASK(_slot_); ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per &= ~M8XX_PCMCIA_MASK(_slot_); /* turn off interrupt and disable CxOE */ M8XX_PGCRX(_slot_) = M8XX_PGCRX_CXOE; /* turn off memory windows */ for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { w->or = 0; /* set to not valid */ w++; } /* turn off voltage */ voltage_set(_slot_, 0, 0); /* disable external hardware */ hardware_disable(_slot_); } free_irq(pcmcia_schlvl, NULL);}/* ------------------------------------------------------------------------- */static int __init m8xx_init(void){ servinfo_t serv; pcmcia_win_t *w; u_int k, m;#if (PCMCIA_SOCKETS_NO == 2) u_int _slot_;#endif PCMCIA_INFO("%s\n", version); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { PCMCIA_ERROR("Card Services release does not match!\n"); return -EINVAL; } PCMCIA_INFO(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG " with IRQ %u.\n", pcmcia_schlvl); /* Configure Status change interrupt */ if(request_8xxirq(pcmcia_schlvl, m8xx_interrupt, 0, "m8xx_pcmcia", NULL)) { PCMCIA_ERROR("Cannot allocate IRQ %u for SCHLVL!\n", pcmcia_schlvl); return -1; } w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; for(k = 0; k < PCMCIA_SOCKETS_NO; k++) { /* Setup internal hardware */#if (PCMCIA_SOCKETS_NO == 2) _slot_ = socket[k].slot = k;#else socket[k].slot = _slot_;#endif ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = M8XX_PCMCIA_MASK(_slot_); ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per &= ~M8XX_PCMCIA_MASK(_slot_); /* connect interrupt and disable CxOE */ M8XX_PGCRX(_slot_) = M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16); /* intialize the fixed memory windows */ for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { w->br = PCMCIA_MEM_WIN_BASE + (PCMCIA_MEM_WIN_SIZE * (m + k * PCMCIA_MEM_WIN_NO)); w->or = 0; /* set to not valid */ DEBUG(3,"Socket %u: MemWin %u: Base 0x%08x.\n", k, m, w->br); w++; } /* turn off voltage */ voltage_set(_slot_, 0, 0); /* Enable external hardware */ hardware_enable(_slot_); } if(register_ss_entry(PCMCIA_SOCKETS_NO, &m8xx_service) != 0) { PCMCIA_ERROR("register_ss_entry() failed.\n"); m8xx_shutdown(); return -ENODEV; } return 0; }/* ------------------------------------------------------------------------- */static void __exit m8xx_exit(void){ unregister_ss_entry(&m8xx_service); m8xx_shutdown();}/* ------------------------------------------------------------------------- */static void m8xx_interrupt(int irq, void *dev, struct pt_regs *regs){ socket_info_t *s; event_table_t *e; u_int events, pscr, pipr, k;#if (PCMCIA_SOCKETS_NO == 2) u_int _slot_;#endif DEBUG(3,"Interrupt!\n"); /* get interrupt sources */ pscr = ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr; pipr = ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr; s = &socket[0]; for(k = 0; k < PCMCIA_SOCKETS_NO; k++) { if(s->handler) { e = &s->events[0]; events = 0;#if (PCMCIA_SOCKETS_NO == 2) _slot_ = s->slot;#endif while(e->regbit) { if(pscr & e->regbit) events |= e->eventbit; e++; } /* * report only if both card detect signals are the same * not too nice done, * we depend on that CD2 is the bit to the left of CD1... */ if(events & SS_DETECT) if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^ (pipr & M8XX_PCMCIA_CD1(_slot_))) events &= ~SS_DETECT;#ifdef PCMCIA_GLITCHY_CD /* * I've experienced CD problems with my ADS board. * We make an extra check to see if there was a * real change of Card detection. */ if((events & SS_DETECT) && ((pipr & (M8XX_PCMCIA_CD2(_slot_) | M8XX_PCMCIA_CD1(_slot_))) == 0) && (s->state.Vcc | s->state.Vpp)) { events &= ~SS_DETECT; printk( "CD glitch workaround - CD = 0x%08x!\n", (pipr & (M8XX_PCMCIA_CD2(_slot_) | M8XX_PCMCIA_CD1(_slot_)))); }#endif /* call the handler */ DEBUG(3,"slot %u: events = 0x%02x, pscr = 0x%08x, " "pipr = 0x%08x\n", _slot_, events, pscr, pipr); if(events) s->handler(s->info, events); } s++; } /* clear the interrupt sources */ ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr; DEBUG(3,"Interrupt done.\n"); }/* ------------------------------------------------------------------------- */static u_int m8xx_get_graycode(u_int size){ u_int k; for(k = 0; k < M8XX_SIZES_NO; k++) if(m8xx_size_to_gray[k] == size) break; if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1)) k = -1; return k;}/* ------------------------------------------------------------------------- */static u_int m8xx_get_speed(u_int ns, u_int is_io){ u_int reg, clocks, psst, psl, psht; if(!ns) { /* * We get called with IO maps setup to 0ns * if not specified by the user. * They should be 255ns. */ if(is_io) ns = 255; else ns = 100; /* fast memory if 0 */ } /* * In PSST, PSL, PSHT fields we tell the controller * timing parameters in CLKOUT clock cycles. * CLKOUT is the same as GCLK2_50. *//* how we want to adjust the timing - in percent */#define ADJ 180 /* 80 % longer accesstime - to be sure */ clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000; clocks = (clocks * ADJ) / (100*1000); if(clocks >= PCMCIA_BMT_LIMIT) { printk( "Max access time limit reached\n"); clocks = PCMCIA_BMT_LIMIT-1; } psst = clocks / 7; /* setup time */ psht = clocks / 7; /* hold time */ psl = (clocks * 5) / 7; /* strobe length */ psst += clocks - (psst + psht + psl); reg = psst << 12; reg |= psl << 7; reg |= psht << 16; return reg;}/* ------------------------------------------------------------------------- */ static int m8xx_register_callback(u_short lsock, ss_callback_t *call){ if (call == NULL) { socket[lsock].handler = NULL; MOD_DEC_USE_COUNT; } else { MOD_INC_USE_COUNT; socket[lsock].handler = call->handler; socket[lsock].info = call->info; } return 0;}/* ------------------------------------------------------------------------- */static int m8xx_get_status(u_short lsock, u_int *value){ socket_info_t *s = &socket[lsock]; u_int pipr, reg;#if (PCMCIA_SOCKETS_NO == 2) u_int _slot_ = s->slot;#endif pipr = ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr; *value = ((pipr & (M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_))) == 0) ? SS_DETECT : 0; *value |= (pipr & M8XX_PCMCIA_WP(_slot_)) ? SS_WRPROT : 0; if (s->state.flags & SS_IOCARD) *value |= (pipr & M8XX_PCMCIA_BVD1(_slot_)) ? SS_STSCHG : 0; else { *value |= (pipr & M8XX_PCMCIA_RDY(_slot_)) ? SS_READY : 0; *value |= (pipr & M8XX_PCMCIA_BVD1(_slot_)) ? SS_BATDEAD : 0; *value |= (pipr & M8XX_PCMCIA_BVD2(_slot_)) ? SS_BATWARN : 0; } if (s->state.Vcc | s->state.Vpp) *value |= SS_POWERON; /* * Voltage detection: * This driver only supports 16-Bit pc-cards. * Cardbus is not handled here. * * To determine what voltage to use we must read the VS1 and VS2 pin. * Depending on what socket type is present, * different combinations mean different things. * * Card Key Socket Key VS1 VS2 Card Vcc for CIS parse * * 5V 5V, LV* NC NC 5V only 5V (if available) * * 5V 5V, LV* GND NC 5 or 3.3V as low as possible * * 5V 5V, LV* GND GND 5, 3.3, x.xV as low as possible * * LV* 5V - - shall not fit into socket * * LV* LV* GND NC 3.3V only 3.3V * * LV* LV* NC GND x.xV x.xV (if avail.) * * LV* LV* GND GND 3.3 or x.xV as low as possible * * *LV means Low Voltage * * * That gives us the following table: * * Socket VS1 VS2 Voltage * * 5V NC NC 5V * 5V NC GND none (should not be possible) * 5V GND NC >= 3.3V * 5V GND GND >= x.xV * * LV NC NC 5V (if available) * LV NC GND x.xV (if available) * LV GND NC 3.3V * LV GND GND >= x.xV * * So, how do I determine if I have a 5V or a LV * socket on my board? Look at the socket! * * * Socket with 5V key: * ++--------------------------------------------+ * || | * || || * || || * | | * +---------------------------------------------+ * * Socket with LV key: * ++--------------------------------------------+ * || | * | || * | || * | | * +---------------------------------------------+ * * * With other words - LV only cards does not fit * into the 5V socket! */ /* read out VS1 and VS2 */ reg = (pipr & M8XX_PCMCIA_VS_MASK(_slot_)) >> M8XX_PCMCIA_VS_SHIFT(_slot_); if(socket_get(_slot_) == PCMCIA_SOCKET_KEY_LV) { switch(reg) { case 1: *value |= SS_3VCARD; break; /* GND, NC - 3.3V only */ case 2: *value |= SS_XVCARD; break; /* NC. GND - x.xV only */ }; } DEBUG(3,"GetStatus(%d) = %#2.2x\n", lsock, *value); return 0;} /* ------------------------------------------------------------------------- */static int m8xx_inquire_socket(u_short lsock, socket_cap_t *cap){ *cap = capabilities; return 0;}/* ------------------------------------------------------------------------- */static int m8xx_get_socket(u_short lsock, socket_state_t *state){ *state = socket[lsock].state; /* copy the whole structure */ DEBUG(3,"GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -