hvcs.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,667 行 · 第 1/4 页
C
1,667 行
memcpy(&hvcsd->buffer[hvcsd->chars_in_buffer], &charbuf[total_sent], tosend); hvcsd->chars_in_buffer += tosend; result = 0; /* * If this is true then we don't want to try writing to the * hypervisor because that is the kernel_threads job now. We'll * just add to the buffer. */ if (!(hvcsd->todo_mask & HVCS_TRY_WRITE)) /* won't send partial writes */ result = hvc_put_chars(unit_address, &hvcsd->buffer[0], hvcsd->chars_in_buffer); /* * Since we know we have enough room in hvcsd->buffer for * tosend we record that it was sent regardless of whether the * hypervisor actually took it because we have it buffered. */ total_sent+=tosend; count-=tosend; if (result == 0) { hvcsd->todo_mask |= HVCS_TRY_WRITE; hvcs_kick(); break; } hvcsd->chars_in_buffer = 0; /* * Test after the chars_in_buffer reset otherwise this could * deadlock our writes if hvc_put_chars fails. */ if (result < 0) break; } spin_unlock_irqrestore(&hvcsd->lock, flags); if (from_user) kfree(charbuf); if (result == -1) return -EIO; else return total_sent;}/* * This is really asking how much can we guarentee that we can send or that we * absolutely WILL BUFFER if we can't send it. This driver MUST honor the * return value, hence the reason for hvcs_struct buffering. */static int hvcs_write_room(struct tty_struct *tty){ struct hvcs_struct *hvcsd = tty->driver_data; if (!hvcsd || hvcsd->open_count <= 0) return 0; return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;}static int hvcs_chars_in_buffer(struct tty_struct *tty){ struct hvcs_struct *hvcsd = tty->driver_data; return hvcsd->chars_in_buffer;}static struct tty_operations hvcs_ops = { .open = hvcs_open, .close = hvcs_close, .hangup = hvcs_hangup, .write = hvcs_write, .write_room = hvcs_write_room, .chars_in_buffer = hvcs_chars_in_buffer, .unthrottle = hvcs_unthrottle, .throttle = hvcs_throttle,};static int hvcs_alloc_index_list(int n){ int i; hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); if (!hvcs_index_list) return -ENOMEM; hvcs_index_count = n; for(i = 0; i < hvcs_index_count; i++) hvcs_index_list[i] = -1; return 0;}static void hvcs_free_index_list(void){ /* Paranoia check to be thorough. */ if (hvcs_index_list) { kfree(hvcs_index_list); hvcs_index_list = NULL; hvcs_index_count = 0; }}static int __init hvcs_module_init(void){ int rc; int num_ttys_to_alloc; printk(KERN_INFO "Initializing %s\n", hvcs_driver_string); /* Has the user specified an overload with an insmod param? */ if (hvcs_parm_num_devs <= 0 || (hvcs_parm_num_devs > HVCS_MAX_SERVER_ADAPTERS)) { num_ttys_to_alloc = HVCS_DEFAULT_SERVER_ADAPTERS; } else num_ttys_to_alloc = hvcs_parm_num_devs; hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc); if (!hvcs_tty_driver) return -ENOMEM; if (hvcs_alloc_index_list(num_ttys_to_alloc)) return -ENOMEM; hvcs_tty_driver->owner = THIS_MODULE; hvcs_tty_driver->driver_name = hvcs_driver_name; hvcs_tty_driver->name = hvcs_device_node; /* * We'll let the system assign us a major number, indicated by leaving * it blank. */ hvcs_tty_driver->minor_start = HVCS_MINOR_START; hvcs_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; /* * We role our own so that we DONT ECHO. We can't echo because the * device we are connecting to already echoes by default and this would * throw us into a horrible recursive echo-echo-echo loop. */ hvcs_tty_driver->init_termios = hvcs_tty_termios; hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hvcs_tty_driver, &hvcs_ops); /* * The following call will result in sysfs entries that denote the * dynamically assigned major and minor numbers for our devices. */ if (tty_register_driver(hvcs_tty_driver)) { printk(KERN_ERR "HVCS: registration " " as a tty driver failed.\n"); hvcs_free_index_list(); put_tty_driver(hvcs_tty_driver); return -EIO; } hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!hvcs_pi_buff) { tty_unregister_driver(hvcs_tty_driver); hvcs_free_index_list(); put_tty_driver(hvcs_tty_driver); return -ENOMEM; } hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); if (IS_ERR(hvcs_task)) { printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); kfree(hvcs_pi_buff); tty_unregister_driver(hvcs_tty_driver); hvcs_free_index_list(); put_tty_driver(hvcs_tty_driver); return -EIO; } rc = vio_register_driver(&hvcs_vio_driver); /* * This needs to be done AFTER the vio_register_driver() call or else * the kobjects won't be initialized properly. */ hvcs_create_driver_attrs(); printk(KERN_INFO "HVCS: driver module inserted.\n"); return rc;}static void __exit hvcs_module_exit(void){ /* * This driver receives hvcs_remove callbacks for each device upon * module removal. */ /* * This synchronous operation will wake the khvcsd kthread if it is * asleep and will return when khvcsd has terminated. */ kthread_stop(hvcs_task); spin_lock(&hvcs_pi_lock); kfree(hvcs_pi_buff); hvcs_pi_buff = NULL; spin_unlock(&hvcs_pi_lock); hvcs_remove_driver_attrs(); vio_unregister_driver(&hvcs_vio_driver); tty_unregister_driver(hvcs_tty_driver); hvcs_free_index_list(); put_tty_driver(hvcs_tty_driver); printk(KERN_INFO "HVCS: driver module removed.\n");}module_init(hvcs_module_init);module_exit(hvcs_module_exit);static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod){ return viod->dev.driver_data;}/* The sysfs interface for the driver and devices */static ssize_t hvcs_partner_vtys_show(struct device *dev, char *buf){ struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); unsigned long flags; int retval; spin_lock_irqsave(&hvcsd->lock, flags); retval = sprintf(buf, "%X\n", hvcsd->p_unit_address); spin_unlock_irqrestore(&hvcsd->lock, flags); return retval;}static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL);static ssize_t hvcs_partner_clcs_show(struct device *dev, char *buf){ struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); unsigned long flags; int retval; spin_lock_irqsave(&hvcsd->lock, flags); retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); spin_unlock_irqrestore(&hvcsd->lock, flags); return retval;}static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL);static ssize_t hvcs_current_vty_store(struct device *dev, const char * buf, size_t count){ /* * Don't need this feature at the present time because firmware doesn't * yet support multiple partners. */ printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n"); return -EPERM;}static ssize_t hvcs_current_vty_show(struct device *dev, char *buf){ struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); unsigned long flags; int retval; spin_lock_irqsave(&hvcsd->lock, flags); retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); spin_unlock_irqrestore(&hvcsd->lock, flags); return retval;}static DEVICE_ATTR(current_vty, S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store);static ssize_t hvcs_vterm_state_store(struct device *dev, const char *buf, size_t count){ struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); unsigned long flags; /* writing a '0' to this sysfs entry will result in the disconnect. */ if (simple_strtol(buf, NULL, 0) != 0) return -EINVAL; spin_lock_irqsave(&hvcsd->lock, flags); if (hvcsd->open_count > 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); printk(KERN_INFO "HVCS: vterm state unchanged. " "The hvcs device node is still in use.\n"); return -EPERM; } if (hvcsd->connected == 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); printk(KERN_INFO "HVCS: vterm state unchanged. The" " vty-server is not connected to a vty.\n"); return -EPERM; } hvcs_partner_free(hvcsd); printk(KERN_INFO "HVCS: Closed vty-server@%X and" " partner vty@%X:%d connection.\n", hvcsd->vdev->unit_address, hvcsd->p_unit_address, (uint32_t)hvcsd->p_partition_ID); spin_unlock_irqrestore(&hvcsd->lock, flags); return count;}static ssize_t hvcs_vterm_state_show(struct device *dev, char *buf){ struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); unsigned long flags; int retval; spin_lock_irqsave(&hvcsd->lock, flags); retval = sprintf(buf, "%d\n", hvcsd->connected); spin_unlock_irqrestore(&hvcsd->lock, flags); return retval;}static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, hvcs_vterm_state_show, hvcs_vterm_state_store);static ssize_t hvcs_index_show(struct device *dev, char *buf){ struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); unsigned long flags; int retval; spin_lock_irqsave(&hvcsd->lock, flags); retval = sprintf(buf, "%d\n", hvcsd->index); spin_unlock_irqrestore(&hvcsd->lock, flags); return retval;}static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL);static struct attribute *hvcs_attrs[] = { &dev_attr_partner_vtys.attr, &dev_attr_partner_clcs.attr, &dev_attr_current_vty.attr, &dev_attr_vterm_state.attr, &dev_attr_index.attr, NULL,};static struct attribute_group hvcs_attr_group = { .attrs = hvcs_attrs,};static void hvcs_create_device_attrs(struct hvcs_struct *hvcsd){ struct vio_dev *vdev = hvcsd->vdev; sysfs_create_group(&vdev->dev.kobj, &hvcs_attr_group);}static void hvcs_remove_device_attrs(struct vio_dev *vdev){ sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group);}static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf){ /* A 1 means it is updating, a 0 means it is done updating */ return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status);}static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf, size_t count){ if ((simple_strtol(buf, NULL, 0) != 1) && (hvcs_rescan_status != 0)) return -EINVAL; hvcs_rescan_status = 1; printk(KERN_INFO "HVCS: rescanning partner info for all" " vty-servers.\n"); hvcs_rescan_devices_list(); hvcs_rescan_status = 0; return count;}static DRIVER_ATTR(rescan, S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store);static void hvcs_create_driver_attrs(void){ struct device_driver *driverfs = &(hvcs_vio_driver.driver); driver_create_file(driverfs, &driver_attr_rescan);}static void hvcs_remove_driver_attrs(void){ struct device_driver *driverfs = &(hvcs_vio_driver.driver); driver_remove_file(driverfs, &driver_attr_rescan);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?