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 + -
显示快捷键?