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

📄 hp_sdc_rtc.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	uint8_t tseq[6] = {		HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT,		0, 3, 0, 0, 0	};	t.endidx = 6;	if (0xffffff < setto->tv_sec) return -1;	tenms  = setto->tv_sec * 100;	if (0xffffff < setto->tv_usec / 10000) return -1;	tenms += setto->tv_usec / 10000;	if (tenms > 0xffffff) return -1;	tseq[1] = setcmd;	tseq[3] = (uint8_t)(tenms & 0xff);	tseq[4] = (uint8_t)((tenms >> 8)  & 0xff);	tseq[5] = (uint8_t)((tenms >> 16)  & 0xff);	t.seq =			tseq;	if (hp_sdc_enqueue_transaction(&t)) { 		return -1;	}	return 0;}static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin){        return -ESPIPE;}static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,			       size_t count, loff_t *ppos) {	ssize_t retval;        if (count < sizeof(unsigned long))                return -EINVAL;	retval = put_user(68, (unsigned long *)buf);	return retval;}static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait){        unsigned long l;	l = 0;        if (l != 0)                return POLLIN | POLLRDNORM;        return 0;}static int hp_sdc_rtc_open(struct inode *inode, struct file *file){        return 0;}static int hp_sdc_rtc_release(struct inode *inode, struct file *file){	/* Turn off interrupts? */        if (file->f_flags & FASYNC) {                hp_sdc_rtc_fasync (-1, file, 0);        }        return 0;}static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on){        return fasync_helper (fd, filp, on, &hp_sdc_rtc_async_queue);}static int hp_sdc_rtc_proc_output (char *buf){#define YN(bit) ("no")#define NY(bit) ("yes")        char *p;        struct rtc_time tm;	struct timeval tv;	memset(&tm, 0, sizeof(struct rtc_time));	p = buf;	if (hp_sdc_rtc_read_bbrtc(&tm)) {		p += sprintf(p, "BBRTC\t\t: READ FAILED!\n");	} else {		p += sprintf(p,			     "rtc_time\t: %02d:%02d:%02d\n"			     "rtc_date\t: %04d-%02d-%02d\n"			     "rtc_epoch\t: %04lu\n",			     tm.tm_hour, tm.tm_min, tm.tm_sec,			     tm.tm_year + 1900, tm.tm_mon + 1, 			     tm.tm_mday, epoch);	}	if (hp_sdc_rtc_read_rt(&tv)) {		p += sprintf(p, "i8042 rtc\t: READ FAILED!\n");	} else {		p += sprintf(p, "i8042 rtc\t: %ld.%02d seconds\n", 			     tv.tv_sec, tv.tv_usec/1000);	}	if (hp_sdc_rtc_read_fhs(&tv)) {		p += sprintf(p, "handshake\t: READ FAILED!\n");	} else {        	p += sprintf(p, "handshake\t: %ld.%02d seconds\n", 			     tv.tv_sec, tv.tv_usec/1000);	}	if (hp_sdc_rtc_read_mt(&tv)) {		p += sprintf(p, "alarm\t\t: READ FAILED!\n");	} else {		p += sprintf(p, "alarm\t\t: %ld.%02d seconds\n", 			     tv.tv_sec, tv.tv_usec/1000);	}	if (hp_sdc_rtc_read_dt(&tv)) {		p += sprintf(p, "delay\t\t: READ FAILED!\n");	} else {		p += sprintf(p, "delay\t\t: %ld.%02d seconds\n", 			     tv.tv_sec, tv.tv_usec/1000);	}	if (hp_sdc_rtc_read_ct(&tv)) {		p += sprintf(p, "periodic\t: READ FAILED!\n");	} else {		p += sprintf(p, "periodic\t: %ld.%02d seconds\n", 			     tv.tv_sec, tv.tv_usec/1000);	}        p += sprintf(p,                     "DST_enable\t: %s\n"                     "BCD\t\t: %s\n"                     "24hr\t\t: %s\n"                     "square_wave\t: %s\n"                     "alarm_IRQ\t: %s\n"                     "update_IRQ\t: %s\n"                     "periodic_IRQ\t: %s\n"		     "periodic_freq\t: %ld\n"                     "batt_status\t: %s\n",                     YN(RTC_DST_EN),                     NY(RTC_DM_BINARY),                     YN(RTC_24H),                     YN(RTC_SQWE),                     YN(RTC_AIE),                     YN(RTC_UIE),                     YN(RTC_PIE),                     1UL,                     1 ? "okay" : "dead");        return  p - buf;#undef YN#undef NY}static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off,                         int count, int *eof, void *data){	int len = hp_sdc_rtc_proc_output (page);        if (len <= off+count) *eof = 1;        *start = page + off;        len -= off;        if (len>count) len = count;        if (len<0) len = 0;        return len;}static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, 			    unsigned int cmd, unsigned long arg){#if 1	return -EINVAL;#else	        struct rtc_time wtime; 	struct timeval ttime;	int use_wtime = 0;	/* This needs major work. */        switch (cmd) {        case RTC_AIE_OFF:       /* Mask alarm int. enab. bit    */        case RTC_AIE_ON:        /* Allow alarm interrupts.      */	case RTC_PIE_OFF:       /* Mask periodic int. enab. bit */        case RTC_PIE_ON:        /* Allow periodic ints          */        case RTC_UIE_ON:        /* Allow ints for RTC updates.  */        case RTC_UIE_OFF:       /* Allow ints for RTC updates.  */        {		/* We cannot mask individual user timers and we		   cannot tell them apart when they occur, so it 		   would be disingenuous to succeed these IOCTLs */		return -EINVAL;        }        case RTC_ALM_READ:      /* Read the present alarm time */        {		if (hp_sdc_rtc_read_mt(&ttime)) return -EFAULT;		if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT;		wtime.tm_hour = ttime.tv_sec / 3600;  ttime.tv_sec %= 3600;		wtime.tm_min  = ttime.tv_sec / 60;    ttime.tv_sec %= 60;		wtime.tm_sec  = ttime.tv_sec;                		break;        }        case RTC_IRQP_READ:     /* Read the periodic IRQ rate.  */        {                return put_user(hp_sdc_rtc_freq, (unsigned long *)arg);        }        case RTC_IRQP_SET:      /* Set periodic IRQ rate.       */        {                /*                  * The max we can do is 100Hz.		 */                if ((arg < 1) || (arg > 100)) return -EINVAL;		ttime.tv_sec = 0;		ttime.tv_usec = 1000000 / arg;		if (hp_sdc_rtc_set_ct(&ttime)) return -EFAULT;		hp_sdc_rtc_freq = arg;                return 0;        }        case RTC_ALM_SET:       /* Store a time into the alarm */        {                /*                 * This expects a struct hp_sdc_rtc_time. Writing 0xff means                 * "don't care" or "match all" for PC timers.  The HP SDC		 * does not support that perk, but it could be emulated fairly		 * easily.  Only the tm_hour, tm_min and tm_sec are used.		 * We could do it with 10ms accuracy with the HP SDC, if the 		 * rtc interface left us a way to do that.                 */                struct hp_sdc_rtc_time alm_tm;                if (copy_from_user(&alm_tm, (struct hp_sdc_rtc_time*)arg,                                   sizeof(struct hp_sdc_rtc_time)))                       return -EFAULT;                if (alm_tm.tm_hour > 23) return -EINVAL;		if (alm_tm.tm_min  > 59) return -EINVAL;		if (alm_tm.tm_sec  > 59) return -EINVAL;  		ttime.sec = alm_tm.tm_hour * 3600 + 		  alm_tm.tm_min * 60 + alm_tm.tm_sec;		ttime.usec = 0;		if (hp_sdc_rtc_set_mt(&ttime)) return -EFAULT;                return 0;        }        case RTC_RD_TIME:       /* Read the time/date from RTC  */        {		if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT;                break;        }        case RTC_SET_TIME:      /* Set the RTC */        {                struct rtc_time hp_sdc_rtc_tm;                unsigned char mon, day, hrs, min, sec, leap_yr;                unsigned int yrs;                if (!capable(CAP_SYS_TIME))                        return -EACCES;		if (copy_from_user(&hp_sdc_rtc_tm, (struct rtc_time *)arg,                                   sizeof(struct rtc_time)))                        return -EFAULT;                yrs = hp_sdc_rtc_tm.tm_year + 1900;                mon = hp_sdc_rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */                day = hp_sdc_rtc_tm.tm_mday;                hrs = hp_sdc_rtc_tm.tm_hour;                min = hp_sdc_rtc_tm.tm_min;                sec = hp_sdc_rtc_tm.tm_sec;                if (yrs < 1970)                        return -EINVAL;                leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));                if ((mon > 12) || (day == 0))                        return -EINVAL;                if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))                        return -EINVAL;		if ((hrs >= 24) || (min >= 60) || (sec >= 60))                        return -EINVAL;                if ((yrs -= eH) > 255)    /* They are unsigned */                        return -EINVAL;                return 0;        }        case RTC_EPOCH_READ:    /* Read the epoch.      */        {                return put_user (epoch, (unsigned long *)arg);        }        case RTC_EPOCH_SET:     /* Set the epoch.       */        {                /*                  * There were no RTC clocks before 1900.                 */                if (arg < 1900)		  return -EINVAL;		if (!capable(CAP_SYS_TIME))		  return -EACCES;		                epoch = arg;                return 0;        }        default:                return -EINVAL;        }        return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;#endif}static struct file_operations hp_sdc_rtc_fops = {        .owner =	THIS_MODULE,        .llseek =	hp_sdc_rtc_llseek,        .read =		hp_sdc_rtc_read,        .poll =		hp_sdc_rtc_poll,        .ioctl =	hp_sdc_rtc_ioctl,        .open =		hp_sdc_rtc_open,        .release =	hp_sdc_rtc_release,        .fasync =	hp_sdc_rtc_fasync,};static struct miscdevice hp_sdc_rtc_dev = {        .minor =	RTC_MINOR,        .name =		"rtc_HIL",        .fops =		&hp_sdc_rtc_fops};static int __init hp_sdc_rtc_init(void){	int ret;	init_MUTEX(&i8042tregs);	if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr)))		return ret;	misc_register(&hp_sdc_rtc_dev);        create_proc_read_entry ("driver/rtc", 0, 0, 				hp_sdc_rtc_read_proc, NULL);	printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded "			 "(RTC v " RTC_VERSION ")\n");	return 0;}static void __exit hp_sdc_rtc_exit(void){	remove_proc_entry ("driver/rtc", NULL);        misc_deregister(&hp_sdc_rtc_dev);	hp_sdc_release_timer_irq(hp_sdc_rtc_isr);        printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support unloaded\n");}module_init(hp_sdc_rtc_init);module_exit(hp_sdc_rtc_exit);

⌨️ 快捷键说明

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