📄 hwc_rw.c
字号:
return -EIO; default: internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER "unconditional read: invalid response code %x - this " "must not occur in a correct driver, please contact " "author\n", hwcb->response_code); return -EIO; }}static int write_event_mask_1 (void){ unsigned int condition_code; int retval; condition_code = service_call (HWC_CMDW_WRITEMASK, hwc_data.page);#ifdef DUMP_HWC_INIT_ERROR if (condition_code == HWC_NOT_OPERATIONAL) __asm__ ("LHI 1,0xe10\n\t" "L 2,0(%0)\n\t" "LRA 3,0(%1)\n\t" "J .+0\n\t" : : "a" (&condition_code), "a" (hwc_data.page) : "1", "2", "3");#endif switch (condition_code) { case HWC_COMMAND_INITIATED: hwc_data.current_servc = HWC_CMDW_WRITEMASK; hwc_data.current_hwcb = hwc_data.page; retval = condition_code; break; case HWC_BUSY: retval = -EBUSY; break; default: retval = -EIO; } return retval;}static int write_event_mask_2 (u32 ext_int_param){ init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page; int retval = 0; if (hwcb->response_code != 0x0020) {#ifdef DUMP_HWC_INIT_ERROR __asm__ ("LHI 1,0xe11\n\t" "LRA 2,0(%0)\n\t" "L 3,0(%1)\n\t" "J .+0\n\t" : : "a" (hwcb), "a" (&(hwcb->response_code)) : "1", "2", "3");#else retval = -1;#endif } else { if (hwcb->mask_length != 4) {#ifdef DUMP_HWC_INIT_ERROR __asm__ ("LHI 1,0xe52\n\t" "LRA 2,0(%0)\n\t" "J .+0 \n\t" : : "a" (hwcb) : "1", "2");#endif } else { retval += eval_hwc_receive_mask (hwcb->hwc_receive_mask); retval += eval_hwc_send_mask (hwcb->hwc_send_mask); } } hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; return retval;}static int set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct){ int retval = 0; hwc_ioctls_t tmp; if (ioctls->width_htab > MAX_MESSAGE_SIZE) { if (correct) tmp.width_htab = MAX_MESSAGE_SIZE; else retval = -EINVAL; } else tmp.width_htab = ioctls->width_htab; tmp.echo = ioctls->echo; if (ioctls->columns > MAX_MESSAGE_SIZE) { if (correct) tmp.columns = MAX_MESSAGE_SIZE; else retval = -EINVAL; } else tmp.columns = ioctls->columns; tmp.final_nl = ioctls->final_nl; if (ioctls->max_hwcb < 2) { if (correct) tmp.max_hwcb = 2; else retval = -EINVAL; } else tmp.max_hwcb = ioctls->max_hwcb; tmp.tolower = ioctls->tolower; if (ioctls->kmem_hwcb > ioctls->max_hwcb) { if (correct) tmp.kmem_hwcb = ioctls->max_hwcb; else retval = -EINVAL; } else tmp.kmem_hwcb = ioctls->kmem_hwcb; if (ioctls->kmem_hwcb > MAX_KMEM_PAGES) { if (correct) ioctls->kmem_hwcb = MAX_KMEM_PAGES; else retval = -EINVAL; } if (ioctls->kmem_hwcb < 2) { if (correct) ioctls->kmem_hwcb = 2; else retval = -EINVAL; } tmp.delim = ioctls->delim; if (!(retval < 0)) hwc_data.ioctls = tmp; return retval;}int do_hwc_init (void){ int retval; memcpy (hwc_data.page, &init_hwcb_template, sizeof (init_hwcb_t)); do { retval = write_event_mask_1 (); if (retval == -EBUSY) { hwc_data.flags |= HWC_INIT; __ctl_store (cr0, 0, 0); cr0_save = cr0; cr0 |= 0x00000200; cr0 &= 0xFFFFF3AC; __ctl_load (cr0, 0, 0); asm volatile ("STOSM %0,0x01" :"=m" (psw_mask)::"memory"); while (!(hwc_data.flags & HWC_INTERRUPT)) barrier (); asm volatile ("STNSM %0,0xFE" :"=m" (psw_mask)::"memory"); __ctl_load (cr0_save, 0, 0); hwc_data.flags &= ~HWC_INIT; } } while (retval == -EBUSY); if (retval == -EIO) { hwc_data.flags |= HWC_BROKEN; printk (HWC_RW_PRINT_HEADER "HWC not operational\n"); } return retval;}void hwc_interrupt_handler (struct pt_regs *regs, __u16 code);int hwc_init (void){ int retval;#ifdef BUFFER_STRESS_TEST init_hwcb_t *hwcb; int i;#endif if (register_external_interrupt (0x2401, hwc_interrupt_handler) != 0) panic ("Couldn't request external interrupts 0x2401"); spin_lock_init (&hwc_data.lock);#ifdef USE_VM_DETECTION if (MACHINE_IS_VM) { if (hwc_data.init_ioctls.columns > 76) hwc_data.init_ioctls.columns = 76; hwc_data.init_ioctls.tolower = 1; if (!hwc_data.init_ioctls.delim) hwc_data.init_ioctls.delim = DEFAULT_CASE_DELIMITER; } else { hwc_data.init_ioctls.tolower = 0; hwc_data.init_ioctls.delim = 0; }#endif retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1); hwc_data.kmem_start = (unsigned long) alloc_bootmem_low_pages (hwc_data.ioctls.kmem_hwcb * PAGE_SIZE); hwc_data.kmem_end = hwc_data.kmem_start + hwc_data.ioctls.kmem_hwcb * PAGE_SIZE - 1; retval = do_hwc_init (); ctl_set_bit (0, 9);#ifdef BUFFER_STRESS_TEST internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER "use %i bytes for buffering.\n", hwc_data.ioctls.kmem_hwcb * PAGE_SIZE); for (i = 0; i < 500; i++) { hwcb = (init_hwcb_t *) BUF_HWCB; internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER "This is stress test message #%i, free: %i bytes\n", i, MAX_HWCB_ROOM - (hwcb->length + sizeof (mto_t))); }#endif return /*retval */ 0;}signed int hwc_register_calls (hwc_high_level_calls_t * calls){ if (calls == NULL) return -EINVAL; if (hwc_data.calls != NULL) return -EBUSY; hwc_data.calls = calls; return 0;}signed int hwc_unregister_calls (hwc_high_level_calls_t * calls){ if (hwc_data.calls == NULL) return -EINVAL; if (calls != hwc_data.calls) return -EINVAL; hwc_data.calls = NULL; return 0;}int hwc_send (hwc_request_t * req){ unsigned long flags; int retval; int cc; spin_lock_irqsave (&hwc_data.lock, flags); if (!req || !req->callback || !req->block) { retval = -EINVAL; goto unlock; } if (hwc_data.request) { retval = -ENOTSUPP; goto unlock; } cc = service_call (req->word, req->block); switch (cc) { case 0: hwc_data.request = req; hwc_data.current_servc = req->word; hwc_data.current_hwcb = req->block; retval = 0; break; case 2: retval = -EBUSY; break; default: retval = -ENOSYS; } unlock: spin_unlock_irqrestore (&hwc_data.lock, flags); return retval;}EXPORT_SYMBOL (hwc_send);void do_hwc_callback (u32 ext_int_param){ if (!hwc_data.request || !hwc_data.request->callback) return; if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR) != (unsigned long) hwc_data.request->block) return; hwc_data.request->callback (hwc_data.request); hwc_data.request = NULL; hwc_data.current_hwcb = NULL; hwc_data.current_servc = 0;}void hwc_do_interrupt (u32 ext_int_param){ u32 finished_hwcb = ext_int_param & HWC_EXT_INT_PARAM_ADDR; u32 evbuf_pending = ext_int_param & HWC_EXT_INT_PARAM_PEND; if (hwc_data.flags & HWC_PTIMER_RUNS) { del_timer (&hwc_data.poll_timer); hwc_data.flags &= ~HWC_PTIMER_RUNS; } if (finished_hwcb) { if ((unsigned long) hwc_data.current_hwcb != finished_hwcb) { internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER "interrupt: mismatch: " "ext. int param. (0x%x) vs. " "current HWCB (0x%x)\n", ext_int_param, hwc_data.current_hwcb); } else { if (hwc_data.request) { do_hwc_callback (ext_int_param); } else { switch (hwc_data.current_servc) { case HWC_CMDW_WRITEMASK: write_event_mask_2 (ext_int_param); break; case HWC_CMDW_WRITEDATA: write_event_data_2 (ext_int_param); break; case HWC_CMDW_READDATA: unconditional_read_2 (ext_int_param); break; default: } } } } else { if (hwc_data.current_hwcb) { internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER "interrupt: mismatch: " "ext. int. param. (0x%x) vs. " "current HWCB (0x%x)\n", ext_int_param, hwc_data.current_hwcb); } } if (evbuf_pending) { unconditional_read_1 (); } else { write_event_data_1 (); } if (!hwc_data.calls || !hwc_data.calls->wake_up) return; (hwc_data.calls->wake_up) ();}void hwc_interrupt_handler (struct pt_regs *regs, __u16 code){ int cpu = smp_processor_id (); u32 ext_int_param = hwc_ext_int_param (); irq_enter (cpu, 0x2401); if (hwc_data.flags & HWC_INIT) { hwc_data.flags |= HWC_INTERRUPT; } else if (hwc_data.flags & HWC_BROKEN) { if (!do_hwc_init ()) { hwc_data.flags &= ~HWC_BROKEN; internal_print (DELAYED_WRITE, HWC_RW_PRINT_HEADER "delayed HWC setup after" " temporary breakdown" " (ext. int. parameter=0x%x)\n", ext_int_param); } } else { spin_lock (&hwc_data.lock); hwc_do_interrupt (ext_int_param); spin_unlock (&hwc_data.lock); } irq_exit (cpu, 0x2401);}void hwc_unblank (void){ spin_lock (&hwc_data.lock); spin_unlock (&hwc_data.lock); __ctl_store (cr0, 0, 0); cr0_save = cr0; cr0 |= 0x00000200; cr0 &= 0xFFFFF3AC; __ctl_load (cr0, 0, 0); asm volatile ("STOSM %0,0x01":"=m" (psw_mask)::"memory"); while (ALL_HWCB_CHAR) barrier (); asm volatile ("STNSM %0,0xFE":"=m" (psw_mask)::"memory"); __ctl_load (cr0_save, 0, 0);}int hwc_ioctl (unsigned int cmd, unsigned long arg){ hwc_ioctls_t tmp = hwc_data.ioctls; int retval = 0; unsigned long flags; unsigned int obuf; spin_lock_irqsave (&hwc_data.lock, flags); switch (cmd) { case TIOCHWCSHTAB: if (get_user (tmp.width_htab, (ioctl_htab_t *) arg)) goto fault; break; case TIOCHWCSECHO: if (get_user (tmp.echo, (ioctl_echo_t *) arg)) goto fault; break; case TIOCHWCSCOLS: if (get_user (tmp.columns, (ioctl_cols_t *) arg)) goto fault; break; case TIOCHWCSNL: if (get_user (tmp.final_nl, (ioctl_nl_t *) arg)) goto fault; break; case TIOCHWCSOBUF: if (get_user (obuf, (unsigned int *) arg)) goto fault; if (obuf & 0xFFF) tmp.max_hwcb = (((obuf | 0xFFF) + 1) >> 12); else tmp.max_hwcb = (obuf >> 12); break; case TIOCHWCSCASE: if (get_user (tmp.tolower, (ioctl_case_t *) arg)) goto fault; break; case TIOCHWCSDELIM: if (get_user (tmp.delim, (ioctl_delim_t *) arg)) goto fault; break; case TIOCHWCSINIT: retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1); break; case TIOCHWCGHTAB: if (put_user (tmp.width_htab, (ioctl_htab_t *) arg)) goto fault; break; case TIOCHWCGECHO: if (put_user (tmp.echo, (ioctl_echo_t *) arg)) goto fault; break; case TIOCHWCGCOLS: if (put_user (tmp.columns, (ioctl_cols_t *) arg)) goto fault; break; case TIOCHWCGNL: if (put_user (tmp.final_nl, (ioctl_nl_t *) arg)) goto fault; break; case TIOCHWCGOBUF: if (put_user (tmp.max_hwcb, (ioctl_obuf_t *) arg)) goto fault; break; case TIOCHWCGKBUF: if (put_user (tmp.kmem_hwcb, (ioctl_obuf_t *) arg)) goto fault; break; case TIOCHWCGCASE: if (put_user (tmp.tolower, (ioctl_case_t *) arg)) goto fault; break; case TIOCHWCGDELIM: if (put_user (tmp.delim, (ioctl_delim_t *) arg)) goto fault; break;#if 0 case TIOCHWCGINIT: if (put_user (&hwc_data.init_ioctls, (hwc_ioctls_t *) arg)) goto fault; break; case TIOCHWCGCURR: if (put_user (&hwc_data.ioctls, (hwc_ioctls_t *) arg)) goto fault; break;#endif default: goto noioctlcmd; } if (_IOC_DIR (cmd) == _IOC_WRITE) retval = set_hwc_ioctls (&tmp, 0); goto out; fault: retval = -EFAULT; goto out; noioctlcmd: retval = -ENOIOCTLCMD; out: spin_unlock_irqrestore (&hwc_data.lock, flags); return retval;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -