转自:http://blog.csdn.net/goldfighter/article/details/6126178

Linux操作系统内核对RTC的编程详解

Linux内核对RTC的编程

MC146818 RTC芯片(或其他兼容芯片,如DS12887)可以在IRQ8上产生周期性的中断,中断的频率在2HZ~8192HZ之间。与MC146818 RTC对应的设备驱动程序实现在include/linux/rtc.h和drivers/char/rtc.c文件中,对应的设备文件是/dev/rtc(major=10,minor=135,只读字符设备)。因此用户进程可以通过对她进行编程以使得当RTC到达某个特定的时间值时激活 IRQ8线,从而将RTC当作一个闹钟来用。

而Linux内核对RTC的唯一用途就是把RTC用作“离线”或“后台”的时间与日期维护器。当Linux内核启动时,它从RTC中读取时间与日期的基准值。然后再运行期间内核就完全抛开RTC,从而以软件的形式维护系统的当前时间与日期,并在需要时将时间回写到RTC芯片中。

Linux在include/linux/mc146818rtc.h和 include/asm-i386/mc146818rtc.h头文件中分别定义了mc146818 RTC芯片各寄存器的含义以及RTC芯片在i386平台上的I/O端口操作。而通用的RTC接口则声明在include/linux/rtc.h头文件中。

7.2.1 RTC芯片的I/O端口操作

Linux在include/asm-i386/mc146818rtc.h头文件中定义了RTC芯片的I/O端口操作。端口0x70被称为“RTC端口0”,端口0x71被称为“RTC端口1”,如下所示:

#ifndef RTC_PORT
#define RTC_PORT(x) (0x70 + (x))
#define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */
#endif

显然,RTC_PORT(0)就是指端口0x70,RTC_PORT(1)就是指I/O端口0x71。

端口0x70被用作RTC芯片内部寄存器的地址索引端口,而端口0x71则被用作 RTC芯片内部寄存器的数据端口。再读写一个RTC寄存器之前,必须先把该寄存器在RTC芯片内部的地址索引值写到端口0x70中。根据这一点,读写一个 RTC寄存器的宏定义CMOS_READ()和CMOS_WRITE()如下:

#define CMOS_READ(addr) ({ /
outb_p((addr),RTC_PORT(0)); /
inb_p(RTC_PORT(1)); /
})
#define CMOS_WRITE(val, addr) ({ /
outb_p((addr),RTC_PORT(0)); /
outb_p((val),RTC_PORT(1)); /
})
#define RTC_IRQ 8

在上述宏定义中,参数addr是RTC寄存器在芯片内部的地址值,取值范围是0x00~0x3F,参数val是待写入寄存器的值。宏RTC_IRQ是指RTC芯片所连接的中断请求输入线号,通常是8。

7.2.2 对RTC寄存器的定义

Linux在include/linux/mc146818rtc.h这个头文件中定义了RTC各寄存器的含义。

(1)寄存器内部地址索引的定义

Linux内核仅使用RTC芯片的时间与日期寄存器组和控制寄存器组,地址为0x00~0x09之间的10个时间与日期寄存器的定义如下:

#define RTC_SECONDS 0
#define RTC_SECONDS_ALARM 1
#define RTC_MINUTES 2
#define RTC_MINUTES_ALARM 3
#define RTC_HOURS 4
#define RTC_HOURS_ALARM 5
/* RTC_*_alarm is always true if 2 MSBs are set */

  1. define RTC_ALARM_DONT_CARE 0xC0

#define RTC_DAY_OF_WEEK 6
#define RTC_DAY_OF_MONTH 7
#define RTC_MONTH 8
#define RTC_YEAR 9

四个控制寄存器的地址定义如下:

#define RTC_REG_A 10
#define RTC_REG_B 11
#define RTC_REG_C 12
#define RTC_REG_D 13

(2)各控制寄存器的状态位的详细定义

控制寄存器A(0x0A)主要用于选择RTC芯片的工作频率,因此也称为RTC频率选择寄存器。因此Linux用一个宏别名RTC_FREQ_SELECT来表示控制寄存器A,如下:

#define RTC_FREQ_SELECT RTC_REG_A

RTC频率寄存器中的位被分为三组:①bit[7]表示UIP标志;②bit[6:4]用于除法器的频率选择;③bit[3:0]用于速率选择。它们的定义如下:

  1. define RTC_UIP 0x80
  2. define RTC_DIV_CTL 0x70

/* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,… 15=2Hz */

  1. define RTC_RATE_SELECT 0x0F

正如7.1.1.1节所介绍的那样,bit[6:4]有5中可能的取值,分别为除法器选择不同的工作频率或用于重置除法器,各种可能的取值如下定义所示:

/* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */

  1. define RTC_REF_CLCK_4MHZ 0x00
  2. define RTC_REF_CLCK_1MHZ 0x10
  3. define RTC_REF_CLCK_32KHZ 0x20

/* 2 values for divider stage reset, others for "testing purposes only" */

  1. define RTC_DIV_RESET1 0x60
  2. define RTC_DIV_RESET2 0x70

寄存器B中的各位用于使能/禁止RTC的各种特性,因此控制寄存器B(0x0B)也称为“控制寄存器”,Linux用宏别名RTC_CONTROL来表示控制寄存器B,它与其中的各标志位的定义如下所示:

#define RTC_CONTROL RTC_REG_B

  1. define RTC_SET 0x80 /* disable updates for clock setting */
  2. define RTC_PIE 0x40 /* periodic interrupt enable */
  3. define RTC_AIE 0x20 /* alarm interrupt enable */
  4. define RTC_UIE 0x10 /* update-finished interrupt enable */
  5. define RTC_SQWE 0x08 /* enable square-wave output */
  6. define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
  7. define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
  8. define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */

寄存器C是RTC芯片的中断请求状态寄存器,Linux用宏别名RTC_INTR_FLAGS来表示寄存器C,它与其中的各标志位的定义如下所示:

#define RTC_INTR_FLAGS RTC_REG_C
/* caution - cleared by read */

  1. define RTC_IRQF 0x80 /* any of the following 3 is active */
  2. define RTC_PF 0x40
  3. define RTC_AF 0x20
  4. define RTC_UF 0x10

寄存器D仅定义了其最高位bit[7],以表示RTC芯片是否有效。因此寄存器D也称为RTC的有效寄存器。Linux用宏别名RTC_VALID来表示寄存器D,如下:

#define RTC_VALID RTC_REG_D

  1. define RTC_VRT 0x80 /* valid RAM and time */

(3)二进制格式与BCD格式的相互转换

由于时间与日期寄存器中的值可能以BCD格式存储,也可能以二进制格式存储,因此需要定义二进制格式与BCD格式之间的相互转换宏,以方便编程。如下:

#ifndef BCD_TO_BIN
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)»4)*10)
#endif

#ifndef BIN_TO_BCD
#define BIN_TO_BCD(val) ((val)=(((val)/10)«4) + (val)%10)
#endif

7.2.3 内核对RTC的操作

如前所述,Linux内核与RTC进行互操作的时机只有两个:(1)内核在启动时从 RTC中读取启动时的时间与日期;(2)内核在需要时将时间与日期回写到RTC中。为此,Linux内核在 arch/i386/kernel/time.c文件中实现了函数get_cmos_time()来进行对RTC的第一种操作。显然, get_cmos_time()函数仅仅在内核启动时被调用一次。而对于第二种操作,Linux则同样在arch/i386/kernel/time.c 文件中实现了函数set_rtc_mmss(),以支持向RTC中回写当前时间与日期。下面我们将来分析这二个函数的实现。在分析get_cmos_time()函数之前,我们先来看看RTC芯片对其时间与日期寄存器组的更新原理。

(1)Update In Progress

当控制寄存器B中的SET标志位为0时,MC146818芯片每秒都会在芯片内部执行一个“更新周期”(Update Cycle),其作用是增加秒寄存器的值,并检查秒寄存器是否溢出。如果溢出,则增加分钟寄存器的值,如此一致下去直到年寄存器。在“更新周期”期间,时间与日期寄存器组(0x00~0x09)是不可用的,此时如果读取它们的值将得到未定义的值,因为MC146818在整个更新周期期间会把时间与日期寄存器组从CPU总线上脱离,从而防止软件程序读到一个渐变的数据。

在MC146818的输入时钟频率(也即晶体增荡器的频率)为 4.194304MHZ或1.048576MHZ的情况下,“更新周期”需要花费248us,而对于输入时钟频率为32.768KHZ的情况,“更新周期”需要花费1984us=1.984ms。控制寄存器A中的UIP标志位用来表示MC146818是否正处于更新周期中,当UIP从0变为1的那个时刻,就表示MC146818将在稍后马上就开更新周期。在UIP从0变到1的那个时刻与MC146818真正开始Update Cycle的那个时刻之间时有一段时间间隔的,通常是244us。也就是说,在UIP从0变到1的244us之后,时间与日期寄存器组中的值才会真正开始改变,而在这之间的244us间隔内,它们的值并不会真正改变。如下图所示:

(2)get_cmos_time()函数

该函数只被内核的初始化例程time_init()和内核的APM模块所调用。其源码如下:

/* not static: needed by APM */
unsigned long get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
int i;

/* The Linux interpretation of the CMOS clock register contents:

  • When the Update-In-Progress (UIP) flag goes from 1 to 0, the
  • RTC registers show the second which has precisely just started.
  • Let's hope other operating systems interpret the RTC the same way.

*/
/* read RTC exactly on falling edge of update flag */
for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second… */
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
break;
for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
break;
do { /* Isn't this overkill ? UIP above should guarantee consistency */
sec = CMOS_READ(RTC_SECONDS);
min = CMOS_READ(RTC_MINUTES);
hour = CMOS_READ(RTC_HOURS);
day = CMOS_READ(RTC_DAY_OF_MONTH);
mon = CMOS_READ(RTC_MONTH);
year = CMOS_READ(RTC_YEAR);
} while (sec != CMOS_READ(RTC_SECONDS));
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
BCD_TO_BIN(sec);
BCD_TO_BIN(min);
BCD_TO_BIN(hour);
BCD_TO_BIN(day);
BCD_TO_BIN(mon);
BCD_TO_BIN(year);
}
if ((year += 1900) < 1970)
year += 100;
return mktime(year, mon, day, hour, min, sec);
}

对该函数的注释如下:

(1)在从RTC中读取时间时,由于RTC存在Update Cycle,因此软件发出读操作的时机是很重要的。对此,get_cmos_time()函数通过UIP标志位来解决这个问题:第一个for循环不停地读取RTC频率选择寄存器中的UIP标志位,并且只要读到UIP的值为1就马上退出这个for循环。第二个for循环同样不停地读取UIP标志位,但他只要一读到UIP的值为0就马上退出这个for循环。这两个for循环的目的就是要在软件逻辑上同步RTC的Update Cycle,显然第二个for循环最大可能需要2.228ms(TBUC+max(TUC)=244us+1984us=2.228ms)

(2)从第二个for循环退出后,RTC的Update Cycle已经结束。此时我们就已经把当前时间逻辑定准在RTC的当前一秒时间间隔内。也就是说,这是我们就可以开始从RTC寄存器中读取当前时间值。但是要注意,读操作应该保证在244us内完成(准确地说,读操作要在RTC的下一个更新周期开始之前完成,244us的限制是过分偏执的:-)。所以, get_cmos_time()函数接下来通过CMOS_READ()宏从RTC中依次读取秒、分钟、小时、日期、月份和年分。这里的do{}while (sec!=CMOS_READ(RTC_SECOND))循环就是用来确保上述6个读操作必须在下一个Update Cycle开始之前完成。

(3)接下来判定时间的数据格式,PC机中一般总是使用BCD格式的时间,因此需要通过BCD_TO_BIN()宏把BCD格式转换为二进制格式。

(4)接下来对年分进行修正,以将年份转换为“19XX”的格式,如果是1970以前的年份,则将其加上100。

(5)最后调用mktime()函数将当前时间与日期转换为相对于1970-01-01 00:00:00的秒数值,并将其作为函数返回值返回。

函数mktime()定义在include/linux/time.h头文件中,它用来根据Gauss算法将以year/mon/day/hour/min/sec(如1980-12-31 23:59:59)格式表示的时间转换为相对于1970-01-01 00:00:00这个UNIX时间基准以来的相对秒数。其源码如下:

static inline unsigned long
mktime (unsigned int year, unsigned int mon,
unsigned int day, unsigned int hour,
unsigned int min, unsigned int sec)
{
if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
mon += 12; /* Puts Feb last since it has leap day */
year -= 1;
}

return (((
(unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
year*365 - 719499
)*24 + hour /* now have hours */
)*60 + min /* now have minutes */
)*60 + sec; /* finally seconds */
}

(3)set_rtc_mmss()函数

该函数用来更新RTC中的时间,它仅有一个参数nowtime,是以秒数表示的当前时间,其源码如下:

static int set_rtc_mmss(unsigned long nowtime)
{
int retval = 0;
int real_seconds, real_minutes, cmos_minutes;
unsigned char save_control, save_freq_select;

/* gets recalled with irq locally disabled */
spin_lock(&rtc_lock);
save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);

save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);

cmos_minutes = CMOS_READ(RTC_MINUTES);
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
BCD_TO_BIN(cmos_minutes);

/*

  • since we're only adjusting minutes and seconds,
  • don't interfere with hour overflow. This avoids
  • messing with unknown time zones but requires your
  • RTC not to be off by more than 15 minutes

*/
real_seconds = nowtime % 60;
real_minutes = nowtime / 60;
if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
real_minutes += 30; /* correct for half hour time zone */
real_minutes %= 60;

if (abs(real_minutes - cmos_minutes) < 30) {
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BIN_TO_BCD(real_seconds);
BIN_TO_BCD(real_minutes);
}
CMOS_WRITE(real_seconds,RTC_SECONDS);
CMOS_WRITE(real_minutes,RTC_MINUTES);
} else {
printk(KERN_WARNING
"set_rtc_mmss: can't update from %d to %d/n",
cmos_minutes, real_minutes);
retval = -1;
}

/* The following flags have to be released exactly in this order,

  • otherwise the DS12887 (popular MC146818A clone with integrated
  • battery and quartz) will not reset the oscillator and will not
  • update precisely 500 ms later. You won't find this mentioned in
  • the Dallas Semiconductor data sheets, but who believes data
  • sheets anyway … — Markus Kuhn

*/
CMOS_WRITE(save_control, RTC_CONTROL);
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
spin_unlock(&rtc_lock);

return retval;
}

对该函数的注释如下:

(1)首先对自旋锁rtc_lock进行加锁。定义在arch/i386/kernel/time.c文件中的全局自旋锁rtc_lock用来串行化所有CPU对RTC的操作。

(2)接下来,在RTC控制寄存器中设置SET标志位,以便通知RTC软件程序随后马上将要更新它的时间与日期。为此先把RTC_CONTROL寄存器的当前值读到变量save_control中,然后再把值(save_control | RTC_SET)回写到寄存器RTC_CONTROL中。

(3)然后,通过RTC_FREQ_SELECT寄存器中bit[6:4]重启 RTC芯片内部的除法器。为此,类似地先把RTC_FREQ_SELECT寄存器的当前值读到变量save_freq_select中,然后再把值(save_freq_select | RTC_DIV_RESET2)回写到RTC_FREQ_SELECT寄存器中。

(4)接着将RTC_MINUTES寄存器的当前值读到变量cmos_minutes中,并根据需要将它从BCD格式转化为二进制格式。

(5)从nowtime参数中得到当前时间的秒数和分钟数。分别保存到real_seconds和real_minutes变量。注意,这里对于半小时区的情况要修正分钟数real_minutes的值。

(6)然后,在real_minutes与RTC_MINUTES寄存器的原值 cmos_minutes二者相差不超过30分钟的情况下,将real_seconds和real_minutes所表示的时间值写到RTC的秒寄存器和分钟寄存器中。当然,在回写之前要记得把二进制转换为BCD格式。

(7)最后,恢复RTC_CONTROL寄存器和RTC_FREQ_SELECT寄存器原来的值。这二者的先后次序是:先恢复RTC_CONTROL寄存器,再恢复RTC_FREQ_SELECT寄存器。然后在解除自旋锁rtc_lock后就可以返回了。

最后,需要说明的一点是,set_rtc_mmss()函数尽可能在靠近一秒时间间隔的中间位置(也即500ms处)左右被调用。此外,Linux内核对每一次成功的更新RTC时间都留下时间轨迹,它用一个系统全局变量 last_rtc_update来表示内核最近一次成功地对RTC进行更新的时间(单位是秒数)。该变量定义在 arch/i386/kernel/time.c文件中:

/* last time the cmos clock got updated */
static long last_rtc_update;

每一次成功地调用set_rtc_mmss()函数后,内核都会马上将last_rtc_update更新为当前时间。

//********************************************************************************

//********************************************************************************

//********************************************************************************

//********************************************************************************

//********************************************************************************

Linux的RTC驱动相对还是比较简单的,可以将它作为一个普通的字符型设备,或者一个misc设备,也可以是一个平台设备,这都没有关系,主要还是对rtc_ops这个文件操作结构体中的成员填充,这里主要涉及到两个方面比较重要:

1. 在Linux中有硬件时钟与系统时钟等两种时钟。硬件时钟是指主机板上的时钟设备,也就是通常可在BIOS画面设定的时钟。系统时钟则是指kernel中的时钟。当Linux启动时,系统时钟会去读取硬件时钟的设定,之后系统时钟即独立运作。所有Linux相关指令与函数都是读取系统时钟的设定。

系统时钟的设定就是我们常用的date命令,而我们写的RTC驱动就是为硬件时钟服务的,它有属于自己的命令hwclock,因此使用date命令是不可能调用到我们的驱动的(在这点上开始把我郁闷到了,写完驱动之后,傻傻的用date指令来测试,当然结果是什么都没有),我们可以通过hwclock的一些指令来实现更新rtc时钟——也就是系统时钟和硬件时钟的交互。

hwclock –r         显示硬件时钟与日期

hwclock –s         将系统时钟调整为与目前的硬件时钟一致。

hwclock –w        将硬件时钟调整为与目前的系统时钟一致。

2. 第二点就是内核空间和用户空间的交互,在系统启动结束,我们实际是处在用户态,因此我们使用指令输入的内容也是在用户态,而我们的驱动是在内核态的,内核态和用户态是互相不可见的,因此我们需要特殊的函数来实现这两种形态的交互,这就是以下两个函数:

copy_from_user(从用户态到内核态)

copy_to_user   (从内核态到用户态)

当然这两个函数需要我们在内核驱动中实现。

RTC最基本的两个命令就是设置时间,读取时间。

设置时间——设置时间会调用系统默认的RTC_SET_TIME,很显然就是处在用户态的用户将自己所要设置的时间信息传递给内核态,

case RTC_SET_TIME:

{

struct rtc_time rtc_tm;

if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))

return -EFAULT;

sep4020_rtc_settime(&rtc_tm);//把用户态得到的信息传递给设置时间这个函数

return 0;

}

读取时间——设置时间会调用系统默认的RTC_RD_TIME,很显然就是需要通过内核态的驱动将芯片时钟取出,并传递给用户态

case RTC_RD_TIME: /* Read the time/date from RTC */

{

sep4020_rtc_gettime(&septime);//通过驱动的读函数读取芯片时钟

copy_to_user((void *)arg, &septime, sizeof septime);//传递给用户态

}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/myleeming/archive/2008/11/05/3228154.aspx

linux rtc 接口【转】的更多相关文章

  1. linux RTC 驱动模型分析【转】

    转自:http://blog.csdn.net/yaozhenguo2006/article/details/6824970 RTC(real time clock)实时时钟,主要作用是给Linux系 ...

  2. linux驱动基础系列--linux rtc子系统

    前言 linux驱动子系统太多了,连时钟也搞了个子系统,这导致一般的时钟芯片的驱动也会涉及到至少2个子系统,一个是时钟芯片接口子系统(比如I2c接口的时钟芯片),一个是内核给所有时钟芯片提供的rtc子 ...

  3. Linux RTC设备驱动

    1. 在Linux2.6.29内核中,RTC是以平台设备的方式注册进内核的. ① RTC驱动定义于文件:drivers/rtc/rtc-s3c.c static struct platform_dri ...

  4. Linux RTC Test Example rtctest.c hacking

    /********************************************************************** * Linux RTC Test Example rtc ...

  5. Linux驱动程序接口

    §1. Linux驱动程序接口 系统调用是操作系统内核与应用程序之间的接口,设备驱动程序则是操作系统内核与机器硬件的接口.几乎所有的系统操作最终映射到物理设备,除了CPU.内存和少数其它设备,所有的设 ...

  6. [Linux] RTC 读写指令及测试程序

    CPU:RK3288 系统:Linux IC:hym8563 在 Linux 系统中,指令 date 和 hwclock 都可以读写时间 date:读写系统时间,写时间需要管理员权限 hwclock: ...

  7. linux rtc中废弃的接口和新的接口

    1. 废弃的接口 rtc_tm_to_time 2. 替换废弃接口的新接口 rtc_tm_sub

  8. Linux RTC驱动模型分析之rtc-sysfs.c【转】

    转自:https://blog.csdn.net/longwang155069/article/details/52353408 版权声明:本文为博主原创文章,未经博主允许不得转载. https:// ...

  9. [Linux] Linux smaps接口文件结构

    在Linux内核 2.6.16中引入了一个系统内存接口特性,这个接口位于/proc/$pid/目录下的smaps文件中 ,一看内容发现是进程内存映像信息,比同一目录下的maps文件更详细些. 400d ...

随机推荐

  1. Posix线程编程指南(3) 线程同步

    互斥锁 尽管在Posix Thread中同样可以使用IPC的信号量机制来实现互斥锁mutex功能,但显然semphore的功能过于强大了,在Posix Thread中定义了另外一套专门用于线程同步的m ...

  2. 【CentOs】搭建svn服务器

    参考资料: svn攻略: http://blog.csdn.net/colinchan/article/details/1865154 错误解决:http://hi.baidu.com/anglem/ ...

  3. 【BZOJ】【3172】【TJOI2013】单词

    AC自动机 Orz zyf 玛雅一开始连题意都没看懂……意思就是给你一篇文章的N个单词,问每个单词在这篇文章中各出现了几次?(这篇文章=N个单词) 那么我们建个AC自动机……对于每个单词来说,它出现的 ...

  4. PKUSC滚粗记

    本来想考得这么烂还是别写了,后来想想毕竟是我高中难得的一次经历,靠脑子记的话我这脑残患者将来肯定会忘了啊……QwQ 好像跟我一样用这个题目的神犇都签了一本QwQ Day 0 来的路上我校其他三位OIe ...

  5. 【BZOJ】【2661】【Beijing WC2012】连连看

    网络流/费用流/二分图最大权匹配 拆点费用流求最大权匹配……为什么我拿zyf和Hzwer的代码也交不过去……WA了那么多次……so sad 求路过的神牛指导啊>_<万分感谢 //BZOJ ...

  6. WebService流行框架之Axis和CXF

    转自:http://www.cnblogs.com/snake-hand/archive/2013/06/09/3129915.html 前言 上节课我们对WebService进行了简单的介绍,对于其 ...

  7. Environment.SpecialFolder.CommonApplicationData

    private void button1_Click(object sender, EventArgs e) { var path=Environment.GetFolderPath(Environm ...

  8. 关于JS APP

    多屏screen, JS如何路由,如何换页,导航.通过JS来实现. 当前页面的逻辑通过JS来实现.HTML DOM, Event, Widget. 核心在于function. JS 不仅仅是DOM, ...

  9. iOS7 状态栏 修改为白色字体的步骤

    1在Info.plist中设置UIViewControllerBasedStatusBarAppearance 为NO2 在需要改变状态栏颜色的ViewController中在ViewDidLoad方 ...

  10. 我收集到的最好的jQuery和CSS3导航菜单

    jQuery和CSS3导航菜单在网页设计和开发的重要组成部分之一.利用jQuery+CSS3实现可以做出拥有各种动画效果的漂亮菜单.在这里,我们收集了一些最好的jQuery+CSS3实现的导航菜单. ...