.. | .. |
---|
53 | 53 | |
---|
54 | 54 | #define RTC_VERSION "1.10d" |
---|
55 | 55 | |
---|
56 | | -static DEFINE_MUTEX(hp_sdc_rtc_mutex); |
---|
57 | 56 | static unsigned long epoch = 2000; |
---|
58 | 57 | |
---|
59 | 58 | static struct semaphore i8042tregs; |
---|
60 | | - |
---|
61 | | -static hp_sdc_irqhook hp_sdc_rtc_isr; |
---|
62 | | - |
---|
63 | | -static struct fasync_struct *hp_sdc_rtc_async_queue; |
---|
64 | | - |
---|
65 | | -static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait); |
---|
66 | | - |
---|
67 | | -static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf, |
---|
68 | | - size_t count, loff_t *ppos); |
---|
69 | | - |
---|
70 | | -static long hp_sdc_rtc_unlocked_ioctl(struct file *file, |
---|
71 | | - unsigned int cmd, unsigned long arg); |
---|
72 | | - |
---|
73 | | -static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait); |
---|
74 | | - |
---|
75 | | -static int hp_sdc_rtc_open(struct inode *inode, struct file *file); |
---|
76 | | -static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on); |
---|
77 | 59 | |
---|
78 | 60 | static void hp_sdc_rtc_isr (int irq, void *dev_id, |
---|
79 | 61 | uint8_t status, uint8_t data) |
---|
.. | .. |
---|
283 | 265 | return 0; |
---|
284 | 266 | } |
---|
285 | 267 | |
---|
286 | | - |
---|
287 | | -#if 0 /* not used yet */ |
---|
288 | | -/* Set the i8042 real-time clock */ |
---|
289 | | -static int hp_sdc_rtc_set_rt (struct timeval *setto) |
---|
290 | | -{ |
---|
291 | | - uint32_t tenms; |
---|
292 | | - unsigned int days; |
---|
293 | | - hp_sdc_transaction t; |
---|
294 | | - uint8_t tseq[11] = { |
---|
295 | | - HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, |
---|
296 | | - HP_SDC_CMD_SET_RTMS, 3, 0, 0, 0, |
---|
297 | | - HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, |
---|
298 | | - HP_SDC_CMD_SET_RTD, 2, 0, 0 |
---|
299 | | - }; |
---|
300 | | - |
---|
301 | | - t.endidx = 10; |
---|
302 | | - |
---|
303 | | - if (0xffff < setto->tv_sec / 86400) return -1; |
---|
304 | | - days = setto->tv_sec / 86400; |
---|
305 | | - if (0xffff < setto->tv_usec / 1000000 / 86400) return -1; |
---|
306 | | - days += ((setto->tv_sec % 86400) + setto->tv_usec / 1000000) / 86400; |
---|
307 | | - if (days > 0xffff) return -1; |
---|
308 | | - |
---|
309 | | - if (0xffffff < setto->tv_sec) return -1; |
---|
310 | | - tenms = setto->tv_sec * 100; |
---|
311 | | - if (0xffffff < setto->tv_usec / 10000) return -1; |
---|
312 | | - tenms += setto->tv_usec / 10000; |
---|
313 | | - if (tenms > 0xffffff) return -1; |
---|
314 | | - |
---|
315 | | - tseq[3] = (uint8_t)(tenms & 0xff); |
---|
316 | | - tseq[4] = (uint8_t)((tenms >> 8) & 0xff); |
---|
317 | | - tseq[5] = (uint8_t)((tenms >> 16) & 0xff); |
---|
318 | | - |
---|
319 | | - tseq[9] = (uint8_t)(days & 0xff); |
---|
320 | | - tseq[10] = (uint8_t)((days >> 8) & 0xff); |
---|
321 | | - |
---|
322 | | - t.seq = tseq; |
---|
323 | | - |
---|
324 | | - if (hp_sdc_enqueue_transaction(&t)) return -1; |
---|
325 | | - return 0; |
---|
326 | | -} |
---|
327 | | - |
---|
328 | | -/* Set the i8042 fast handshake timer */ |
---|
329 | | -static int hp_sdc_rtc_set_fhs (struct timeval *setto) |
---|
330 | | -{ |
---|
331 | | - uint32_t tenms; |
---|
332 | | - hp_sdc_transaction t; |
---|
333 | | - uint8_t tseq[5] = { |
---|
334 | | - HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, |
---|
335 | | - HP_SDC_CMD_SET_FHS, 2, 0, 0 |
---|
336 | | - }; |
---|
337 | | - |
---|
338 | | - t.endidx = 4; |
---|
339 | | - |
---|
340 | | - if (0xffff < setto->tv_sec) return -1; |
---|
341 | | - tenms = setto->tv_sec * 100; |
---|
342 | | - if (0xffff < setto->tv_usec / 10000) return -1; |
---|
343 | | - tenms += setto->tv_usec / 10000; |
---|
344 | | - if (tenms > 0xffff) return -1; |
---|
345 | | - |
---|
346 | | - tseq[3] = (uint8_t)(tenms & 0xff); |
---|
347 | | - tseq[4] = (uint8_t)((tenms >> 8) & 0xff); |
---|
348 | | - |
---|
349 | | - t.seq = tseq; |
---|
350 | | - |
---|
351 | | - if (hp_sdc_enqueue_transaction(&t)) return -1; |
---|
352 | | - return 0; |
---|
353 | | -} |
---|
354 | | - |
---|
355 | | - |
---|
356 | | -/* Set the i8042 match timer (a.k.a. alarm) */ |
---|
357 | | -#define hp_sdc_rtc_set_mt (setto) \ |
---|
358 | | - hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_MT) |
---|
359 | | - |
---|
360 | | -/* Set the i8042 delay timer */ |
---|
361 | | -#define hp_sdc_rtc_set_dt (setto) \ |
---|
362 | | - hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_DT) |
---|
363 | | - |
---|
364 | | -/* Set the i8042 cycle timer (a.k.a. periodic) */ |
---|
365 | | -#define hp_sdc_rtc_set_ct (setto) \ |
---|
366 | | - hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_CT) |
---|
367 | | - |
---|
368 | | -/* Set one of the i8042 3-byte wide timers */ |
---|
369 | | -static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd) |
---|
370 | | -{ |
---|
371 | | - uint32_t tenms; |
---|
372 | | - hp_sdc_transaction t; |
---|
373 | | - uint8_t tseq[6] = { |
---|
374 | | - HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, |
---|
375 | | - 0, 3, 0, 0, 0 |
---|
376 | | - }; |
---|
377 | | - |
---|
378 | | - t.endidx = 6; |
---|
379 | | - |
---|
380 | | - if (0xffffff < setto->tv_sec) return -1; |
---|
381 | | - tenms = setto->tv_sec * 100; |
---|
382 | | - if (0xffffff < setto->tv_usec / 10000) return -1; |
---|
383 | | - tenms += setto->tv_usec / 10000; |
---|
384 | | - if (tenms > 0xffffff) return -1; |
---|
385 | | - |
---|
386 | | - tseq[1] = setcmd; |
---|
387 | | - tseq[3] = (uint8_t)(tenms & 0xff); |
---|
388 | | - tseq[4] = (uint8_t)((tenms >> 8) & 0xff); |
---|
389 | | - tseq[5] = (uint8_t)((tenms >> 16) & 0xff); |
---|
390 | | - |
---|
391 | | - t.seq = tseq; |
---|
392 | | - |
---|
393 | | - if (hp_sdc_enqueue_transaction(&t)) { |
---|
394 | | - return -1; |
---|
395 | | - } |
---|
396 | | - return 0; |
---|
397 | | -} |
---|
398 | | -#endif |
---|
399 | | - |
---|
400 | | -static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf, |
---|
401 | | - size_t count, loff_t *ppos) { |
---|
402 | | - ssize_t retval; |
---|
403 | | - |
---|
404 | | - if (count < sizeof(unsigned long)) |
---|
405 | | - return -EINVAL; |
---|
406 | | - |
---|
407 | | - retval = put_user(68, (unsigned long __user *)buf); |
---|
408 | | - return retval; |
---|
409 | | -} |
---|
410 | | - |
---|
411 | | -static __poll_t hp_sdc_rtc_poll(struct file *file, poll_table *wait) |
---|
412 | | -{ |
---|
413 | | - unsigned long l; |
---|
414 | | - |
---|
415 | | - l = 0; |
---|
416 | | - if (l != 0) |
---|
417 | | - return EPOLLIN | EPOLLRDNORM; |
---|
418 | | - return 0; |
---|
419 | | -} |
---|
420 | | - |
---|
421 | | -static int hp_sdc_rtc_open(struct inode *inode, struct file *file) |
---|
422 | | -{ |
---|
423 | | - return 0; |
---|
424 | | -} |
---|
425 | | - |
---|
426 | | -static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on) |
---|
427 | | -{ |
---|
428 | | - return fasync_helper (fd, filp, on, &hp_sdc_rtc_async_queue); |
---|
429 | | -} |
---|
430 | | - |
---|
431 | 268 | static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) |
---|
432 | 269 | { |
---|
433 | 270 | #define YN(bit) ("no") |
---|
.. | .. |
---|
441 | 278 | seq_puts(m, "BBRTC\t\t: READ FAILED!\n"); |
---|
442 | 279 | } else { |
---|
443 | 280 | seq_printf(m, |
---|
444 | | - "rtc_time\t: %02d:%02d:%02d\n" |
---|
445 | | - "rtc_date\t: %04d-%02d-%02d\n" |
---|
| 281 | + "rtc_time\t: %ptRt\n" |
---|
| 282 | + "rtc_date\t: %ptRd\n" |
---|
446 | 283 | "rtc_epoch\t: %04lu\n", |
---|
447 | | - tm.tm_hour, tm.tm_min, tm.tm_sec, |
---|
448 | | - tm.tm_year + 1900, tm.tm_mon + 1, |
---|
449 | | - tm.tm_mday, epoch); |
---|
| 284 | + &tm, &tm, epoch); |
---|
450 | 285 | } |
---|
451 | 286 | |
---|
452 | 287 | if (hp_sdc_rtc_read_rt(&tv)) { |
---|
.. | .. |
---|
509 | 344 | #undef NY |
---|
510 | 345 | } |
---|
511 | 346 | |
---|
512 | | -static int hp_sdc_rtc_ioctl(struct file *file, |
---|
513 | | - unsigned int cmd, unsigned long arg) |
---|
514 | | -{ |
---|
515 | | -#if 1 |
---|
516 | | - return -EINVAL; |
---|
517 | | -#else |
---|
518 | | - |
---|
519 | | - struct rtc_time wtime; |
---|
520 | | - struct timeval ttime; |
---|
521 | | - int use_wtime = 0; |
---|
522 | | - |
---|
523 | | - /* This needs major work. */ |
---|
524 | | - |
---|
525 | | - switch (cmd) { |
---|
526 | | - |
---|
527 | | - case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ |
---|
528 | | - case RTC_AIE_ON: /* Allow alarm interrupts. */ |
---|
529 | | - case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ |
---|
530 | | - case RTC_PIE_ON: /* Allow periodic ints */ |
---|
531 | | - case RTC_UIE_ON: /* Allow ints for RTC updates. */ |
---|
532 | | - case RTC_UIE_OFF: /* Allow ints for RTC updates. */ |
---|
533 | | - { |
---|
534 | | - /* We cannot mask individual user timers and we |
---|
535 | | - cannot tell them apart when they occur, so it |
---|
536 | | - would be disingenuous to succeed these IOCTLs */ |
---|
537 | | - return -EINVAL; |
---|
538 | | - } |
---|
539 | | - case RTC_ALM_READ: /* Read the present alarm time */ |
---|
540 | | - { |
---|
541 | | - if (hp_sdc_rtc_read_mt(&ttime)) return -EFAULT; |
---|
542 | | - if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT; |
---|
543 | | - |
---|
544 | | - wtime.tm_hour = ttime.tv_sec / 3600; ttime.tv_sec %= 3600; |
---|
545 | | - wtime.tm_min = ttime.tv_sec / 60; ttime.tv_sec %= 60; |
---|
546 | | - wtime.tm_sec = ttime.tv_sec; |
---|
547 | | - |
---|
548 | | - break; |
---|
549 | | - } |
---|
550 | | - case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ |
---|
551 | | - { |
---|
552 | | - return put_user(hp_sdc_rtc_freq, (unsigned long *)arg); |
---|
553 | | - } |
---|
554 | | - case RTC_IRQP_SET: /* Set periodic IRQ rate. */ |
---|
555 | | - { |
---|
556 | | - /* |
---|
557 | | - * The max we can do is 100Hz. |
---|
558 | | - */ |
---|
559 | | - |
---|
560 | | - if ((arg < 1) || (arg > 100)) return -EINVAL; |
---|
561 | | - ttime.tv_sec = 0; |
---|
562 | | - ttime.tv_usec = 1000000 / arg; |
---|
563 | | - if (hp_sdc_rtc_set_ct(&ttime)) return -EFAULT; |
---|
564 | | - hp_sdc_rtc_freq = arg; |
---|
565 | | - return 0; |
---|
566 | | - } |
---|
567 | | - case RTC_ALM_SET: /* Store a time into the alarm */ |
---|
568 | | - { |
---|
569 | | - /* |
---|
570 | | - * This expects a struct hp_sdc_rtc_time. Writing 0xff means |
---|
571 | | - * "don't care" or "match all" for PC timers. The HP SDC |
---|
572 | | - * does not support that perk, but it could be emulated fairly |
---|
573 | | - * easily. Only the tm_hour, tm_min and tm_sec are used. |
---|
574 | | - * We could do it with 10ms accuracy with the HP SDC, if the |
---|
575 | | - * rtc interface left us a way to do that. |
---|
576 | | - */ |
---|
577 | | - struct hp_sdc_rtc_time alm_tm; |
---|
578 | | - |
---|
579 | | - if (copy_from_user(&alm_tm, (struct hp_sdc_rtc_time*)arg, |
---|
580 | | - sizeof(struct hp_sdc_rtc_time))) |
---|
581 | | - return -EFAULT; |
---|
582 | | - |
---|
583 | | - if (alm_tm.tm_hour > 23) return -EINVAL; |
---|
584 | | - if (alm_tm.tm_min > 59) return -EINVAL; |
---|
585 | | - if (alm_tm.tm_sec > 59) return -EINVAL; |
---|
586 | | - |
---|
587 | | - ttime.sec = alm_tm.tm_hour * 3600 + |
---|
588 | | - alm_tm.tm_min * 60 + alm_tm.tm_sec; |
---|
589 | | - ttime.usec = 0; |
---|
590 | | - if (hp_sdc_rtc_set_mt(&ttime)) return -EFAULT; |
---|
591 | | - return 0; |
---|
592 | | - } |
---|
593 | | - case RTC_RD_TIME: /* Read the time/date from RTC */ |
---|
594 | | - { |
---|
595 | | - if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT; |
---|
596 | | - break; |
---|
597 | | - } |
---|
598 | | - case RTC_SET_TIME: /* Set the RTC */ |
---|
599 | | - { |
---|
600 | | - struct rtc_time hp_sdc_rtc_tm; |
---|
601 | | - unsigned char mon, day, hrs, min, sec, leap_yr; |
---|
602 | | - unsigned int yrs; |
---|
603 | | - |
---|
604 | | - if (!capable(CAP_SYS_TIME)) |
---|
605 | | - return -EACCES; |
---|
606 | | - if (copy_from_user(&hp_sdc_rtc_tm, (struct rtc_time *)arg, |
---|
607 | | - sizeof(struct rtc_time))) |
---|
608 | | - return -EFAULT; |
---|
609 | | - |
---|
610 | | - yrs = hp_sdc_rtc_tm.tm_year + 1900; |
---|
611 | | - mon = hp_sdc_rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ |
---|
612 | | - day = hp_sdc_rtc_tm.tm_mday; |
---|
613 | | - hrs = hp_sdc_rtc_tm.tm_hour; |
---|
614 | | - min = hp_sdc_rtc_tm.tm_min; |
---|
615 | | - sec = hp_sdc_rtc_tm.tm_sec; |
---|
616 | | - |
---|
617 | | - if (yrs < 1970) |
---|
618 | | - return -EINVAL; |
---|
619 | | - |
---|
620 | | - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); |
---|
621 | | - |
---|
622 | | - if ((mon > 12) || (day == 0)) |
---|
623 | | - return -EINVAL; |
---|
624 | | - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) |
---|
625 | | - return -EINVAL; |
---|
626 | | - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) |
---|
627 | | - return -EINVAL; |
---|
628 | | - |
---|
629 | | - if ((yrs -= eH) > 255) /* They are unsigned */ |
---|
630 | | - return -EINVAL; |
---|
631 | | - |
---|
632 | | - |
---|
633 | | - return 0; |
---|
634 | | - } |
---|
635 | | - case RTC_EPOCH_READ: /* Read the epoch. */ |
---|
636 | | - { |
---|
637 | | - return put_user (epoch, (unsigned long *)arg); |
---|
638 | | - } |
---|
639 | | - case RTC_EPOCH_SET: /* Set the epoch. */ |
---|
640 | | - { |
---|
641 | | - /* |
---|
642 | | - * There were no RTC clocks before 1900. |
---|
643 | | - */ |
---|
644 | | - if (arg < 1900) |
---|
645 | | - return -EINVAL; |
---|
646 | | - if (!capable(CAP_SYS_TIME)) |
---|
647 | | - return -EACCES; |
---|
648 | | - |
---|
649 | | - epoch = arg; |
---|
650 | | - return 0; |
---|
651 | | - } |
---|
652 | | - default: |
---|
653 | | - return -EINVAL; |
---|
654 | | - } |
---|
655 | | - return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; |
---|
656 | | -#endif |
---|
657 | | -} |
---|
658 | | - |
---|
659 | | -static long hp_sdc_rtc_unlocked_ioctl(struct file *file, |
---|
660 | | - unsigned int cmd, unsigned long arg) |
---|
661 | | -{ |
---|
662 | | - int ret; |
---|
663 | | - |
---|
664 | | - mutex_lock(&hp_sdc_rtc_mutex); |
---|
665 | | - ret = hp_sdc_rtc_ioctl(file, cmd, arg); |
---|
666 | | - mutex_unlock(&hp_sdc_rtc_mutex); |
---|
667 | | - |
---|
668 | | - return ret; |
---|
669 | | -} |
---|
670 | | - |
---|
671 | | - |
---|
672 | | -static const struct file_operations hp_sdc_rtc_fops = { |
---|
673 | | - .owner = THIS_MODULE, |
---|
674 | | - .llseek = no_llseek, |
---|
675 | | - .read = hp_sdc_rtc_read, |
---|
676 | | - .poll = hp_sdc_rtc_poll, |
---|
677 | | - .unlocked_ioctl = hp_sdc_rtc_unlocked_ioctl, |
---|
678 | | - .open = hp_sdc_rtc_open, |
---|
679 | | - .fasync = hp_sdc_rtc_fasync, |
---|
680 | | -}; |
---|
681 | | - |
---|
682 | | -static struct miscdevice hp_sdc_rtc_dev = { |
---|
683 | | - .minor = RTC_MINOR, |
---|
684 | | - .name = "rtc_HIL", |
---|
685 | | - .fops = &hp_sdc_rtc_fops |
---|
686 | | -}; |
---|
687 | | - |
---|
688 | 347 | static int __init hp_sdc_rtc_init(void) |
---|
689 | 348 | { |
---|
690 | 349 | int ret; |
---|
.. | .. |
---|
698 | 357 | |
---|
699 | 358 | if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr))) |
---|
700 | 359 | return ret; |
---|
701 | | - if (misc_register(&hp_sdc_rtc_dev) != 0) |
---|
702 | | - printk(KERN_INFO "Could not register misc. dev for i8042 rtc\n"); |
---|
703 | 360 | |
---|
704 | 361 | proc_create_single("driver/rtc", 0, NULL, hp_sdc_rtc_proc_show); |
---|
705 | 362 | |
---|
.. | .. |
---|
712 | 369 | static void __exit hp_sdc_rtc_exit(void) |
---|
713 | 370 | { |
---|
714 | 371 | remove_proc_entry ("driver/rtc", NULL); |
---|
715 | | - misc_deregister(&hp_sdc_rtc_dev); |
---|
716 | 372 | hp_sdc_release_timer_irq(hp_sdc_rtc_isr); |
---|
717 | 373 | printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support unloaded\n"); |
---|
718 | 374 | } |
---|