diff options
Diffstat (limited to 'drivers/char/hvcs.c')
-rw-r--r-- | drivers/char/hvcs.c | 432 |
1 files changed, 214 insertions, 218 deletions
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 8728255c9463..207f7343ba60 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c | |||
@@ -192,11 +192,13 @@ MODULE_VERSION(HVCS_DRIVER_VERSION); | |||
192 | * that will cause echoing or we'll go into recursive loop echoing chars back | 192 | * that will cause echoing or we'll go into recursive loop echoing chars back |
193 | * and forth with the console drivers. | 193 | * and forth with the console drivers. |
194 | */ | 194 | */ |
195 | static struct termios hvcs_tty_termios = { | 195 | static struct ktermios hvcs_tty_termios = { |
196 | .c_iflag = IGNBRK | IGNPAR, | 196 | .c_iflag = IGNBRK | IGNPAR, |
197 | .c_oflag = OPOST, | 197 | .c_oflag = OPOST, |
198 | .c_cflag = B38400 | CS8 | CREAD | HUPCL, | 198 | .c_cflag = B38400 | CS8 | CREAD | HUPCL, |
199 | .c_cc = INIT_C_CC | 199 | .c_cc = INIT_C_CC, |
200 | .c_ispeed = 38400, | ||
201 | .c_ospeed = 38400 | ||
200 | }; | 202 | }; |
201 | 203 | ||
202 | /* | 204 | /* |
@@ -337,11 +339,6 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp); | |||
337 | static void hvcs_close(struct tty_struct *tty, struct file *filp); | 339 | static void hvcs_close(struct tty_struct *tty, struct file *filp); |
338 | static void hvcs_hangup(struct tty_struct * tty); | 340 | static void hvcs_hangup(struct tty_struct * tty); |
339 | 341 | ||
340 | static void hvcs_create_device_attrs(struct hvcs_struct *hvcsd); | ||
341 | static void hvcs_remove_device_attrs(struct vio_dev *vdev); | ||
342 | static void hvcs_create_driver_attrs(void); | ||
343 | static void hvcs_remove_driver_attrs(void); | ||
344 | |||
345 | static int __devinit hvcs_probe(struct vio_dev *dev, | 342 | static int __devinit hvcs_probe(struct vio_dev *dev, |
346 | const struct vio_device_id *id); | 343 | const struct vio_device_id *id); |
347 | static int __devexit hvcs_remove(struct vio_dev *dev); | 344 | static int __devexit hvcs_remove(struct vio_dev *dev); |
@@ -353,6 +350,172 @@ static void __exit hvcs_module_exit(void); | |||
353 | #define HVCS_TRY_WRITE 0x00000004 | 350 | #define HVCS_TRY_WRITE 0x00000004 |
354 | #define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ) | 351 | #define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ) |
355 | 352 | ||
353 | static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) | ||
354 | { | ||
355 | return viod->dev.driver_data; | ||
356 | } | ||
357 | /* The sysfs interface for the driver and devices */ | ||
358 | |||
359 | static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
360 | { | ||
361 | struct vio_dev *viod = to_vio_dev(dev); | ||
362 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
363 | unsigned long flags; | ||
364 | int retval; | ||
365 | |||
366 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
367 | retval = sprintf(buf, "%X\n", hvcsd->p_unit_address); | ||
368 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
369 | return retval; | ||
370 | } | ||
371 | static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); | ||
372 | |||
373 | static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
374 | { | ||
375 | struct vio_dev *viod = to_vio_dev(dev); | ||
376 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
377 | unsigned long flags; | ||
378 | int retval; | ||
379 | |||
380 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
381 | retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); | ||
382 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
383 | return retval; | ||
384 | } | ||
385 | static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); | ||
386 | |||
387 | static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, | ||
388 | size_t count) | ||
389 | { | ||
390 | /* | ||
391 | * Don't need this feature at the present time because firmware doesn't | ||
392 | * yet support multiple partners. | ||
393 | */ | ||
394 | printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n"); | ||
395 | return -EPERM; | ||
396 | } | ||
397 | |||
398 | static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
399 | { | ||
400 | struct vio_dev *viod = to_vio_dev(dev); | ||
401 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
402 | unsigned long flags; | ||
403 | int retval; | ||
404 | |||
405 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
406 | retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); | ||
407 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
408 | return retval; | ||
409 | } | ||
410 | |||
411 | static DEVICE_ATTR(current_vty, | ||
412 | S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); | ||
413 | |||
414 | static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, | ||
415 | size_t count) | ||
416 | { | ||
417 | struct vio_dev *viod = to_vio_dev(dev); | ||
418 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
419 | unsigned long flags; | ||
420 | |||
421 | /* writing a '0' to this sysfs entry will result in the disconnect. */ | ||
422 | if (simple_strtol(buf, NULL, 0) != 0) | ||
423 | return -EINVAL; | ||
424 | |||
425 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
426 | |||
427 | if (hvcsd->open_count > 0) { | ||
428 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
429 | printk(KERN_INFO "HVCS: vterm state unchanged. " | ||
430 | "The hvcs device node is still in use.\n"); | ||
431 | return -EPERM; | ||
432 | } | ||
433 | |||
434 | if (hvcsd->connected == 0) { | ||
435 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
436 | printk(KERN_INFO "HVCS: vterm state unchanged. The" | ||
437 | " vty-server is not connected to a vty.\n"); | ||
438 | return -EPERM; | ||
439 | } | ||
440 | |||
441 | hvcs_partner_free(hvcsd); | ||
442 | printk(KERN_INFO "HVCS: Closed vty-server@%X and" | ||
443 | " partner vty@%X:%d connection.\n", | ||
444 | hvcsd->vdev->unit_address, | ||
445 | hvcsd->p_unit_address, | ||
446 | (uint32_t)hvcsd->p_partition_ID); | ||
447 | |||
448 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
449 | return count; | ||
450 | } | ||
451 | |||
452 | static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
453 | { | ||
454 | struct vio_dev *viod = to_vio_dev(dev); | ||
455 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
456 | unsigned long flags; | ||
457 | int retval; | ||
458 | |||
459 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
460 | retval = sprintf(buf, "%d\n", hvcsd->connected); | ||
461 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
462 | return retval; | ||
463 | } | ||
464 | static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, | ||
465 | hvcs_vterm_state_show, hvcs_vterm_state_store); | ||
466 | |||
467 | static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
468 | { | ||
469 | struct vio_dev *viod = to_vio_dev(dev); | ||
470 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
471 | unsigned long flags; | ||
472 | int retval; | ||
473 | |||
474 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
475 | retval = sprintf(buf, "%d\n", hvcsd->index); | ||
476 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
477 | return retval; | ||
478 | } | ||
479 | |||
480 | static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); | ||
481 | |||
482 | static struct attribute *hvcs_attrs[] = { | ||
483 | &dev_attr_partner_vtys.attr, | ||
484 | &dev_attr_partner_clcs.attr, | ||
485 | &dev_attr_current_vty.attr, | ||
486 | &dev_attr_vterm_state.attr, | ||
487 | &dev_attr_index.attr, | ||
488 | NULL, | ||
489 | }; | ||
490 | |||
491 | static struct attribute_group hvcs_attr_group = { | ||
492 | .attrs = hvcs_attrs, | ||
493 | }; | ||
494 | |||
495 | static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf) | ||
496 | { | ||
497 | /* A 1 means it is updating, a 0 means it is done updating */ | ||
498 | return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status); | ||
499 | } | ||
500 | |||
501 | static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf, | ||
502 | size_t count) | ||
503 | { | ||
504 | if ((simple_strtol(buf, NULL, 0) != 1) | ||
505 | && (hvcs_rescan_status != 0)) | ||
506 | return -EINVAL; | ||
507 | |||
508 | hvcs_rescan_status = 1; | ||
509 | printk(KERN_INFO "HVCS: rescanning partner info for all" | ||
510 | " vty-servers.\n"); | ||
511 | hvcs_rescan_devices_list(); | ||
512 | hvcs_rescan_status = 0; | ||
513 | return count; | ||
514 | } | ||
515 | |||
516 | static DRIVER_ATTR(rescan, | ||
517 | S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store); | ||
518 | |||
356 | static void hvcs_kick(void) | 519 | static void hvcs_kick(void) |
357 | { | 520 | { |
358 | hvcs_kicked = 1; | 521 | hvcs_kicked = 1; |
@@ -575,7 +738,7 @@ static void destroy_hvcs_struct(struct kobject *kobj) | |||
575 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 738 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
576 | spin_unlock(&hvcs_structs_lock); | 739 | spin_unlock(&hvcs_structs_lock); |
577 | 740 | ||
578 | hvcs_remove_device_attrs(vdev); | 741 | sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group); |
579 | 742 | ||
580 | kfree(hvcsd); | 743 | kfree(hvcsd); |
581 | } | 744 | } |
@@ -608,6 +771,7 @@ static int __devinit hvcs_probe( | |||
608 | { | 771 | { |
609 | struct hvcs_struct *hvcsd; | 772 | struct hvcs_struct *hvcsd; |
610 | int index; | 773 | int index; |
774 | int retval; | ||
611 | 775 | ||
612 | if (!dev || !id) { | 776 | if (!dev || !id) { |
613 | printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); | 777 | printk(KERN_ERR "HVCS: probed with invalid parameter.\n"); |
@@ -658,14 +822,16 @@ static int __devinit hvcs_probe( | |||
658 | * the hvcs_struct has been added to the devices list then the user app | 822 | * the hvcs_struct has been added to the devices list then the user app |
659 | * will get -ENODEV. | 823 | * will get -ENODEV. |
660 | */ | 824 | */ |
661 | |||
662 | spin_lock(&hvcs_structs_lock); | 825 | spin_lock(&hvcs_structs_lock); |
663 | |||
664 | list_add_tail(&(hvcsd->next), &hvcs_structs); | 826 | list_add_tail(&(hvcsd->next), &hvcs_structs); |
665 | |||
666 | spin_unlock(&hvcs_structs_lock); | 827 | spin_unlock(&hvcs_structs_lock); |
667 | 828 | ||
668 | hvcs_create_device_attrs(hvcsd); | 829 | retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group); |
830 | if (retval) { | ||
831 | printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n", | ||
832 | hvcsd->vdev->unit_address); | ||
833 | return retval; | ||
834 | } | ||
669 | 835 | ||
670 | printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); | 836 | printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address); |
671 | 837 | ||
@@ -1354,8 +1520,10 @@ static int __init hvcs_module_init(void) | |||
1354 | if (!hvcs_tty_driver) | 1520 | if (!hvcs_tty_driver) |
1355 | return -ENOMEM; | 1521 | return -ENOMEM; |
1356 | 1522 | ||
1357 | if (hvcs_alloc_index_list(num_ttys_to_alloc)) | 1523 | if (hvcs_alloc_index_list(num_ttys_to_alloc)) { |
1358 | return -ENOMEM; | 1524 | rc = -ENOMEM; |
1525 | goto index_fail; | ||
1526 | } | ||
1359 | 1527 | ||
1360 | hvcs_tty_driver->owner = THIS_MODULE; | 1528 | hvcs_tty_driver->owner = THIS_MODULE; |
1361 | 1529 | ||
@@ -1385,41 +1553,57 @@ static int __init hvcs_module_init(void) | |||
1385 | * dynamically assigned major and minor numbers for our devices. | 1553 | * dynamically assigned major and minor numbers for our devices. |
1386 | */ | 1554 | */ |
1387 | if (tty_register_driver(hvcs_tty_driver)) { | 1555 | if (tty_register_driver(hvcs_tty_driver)) { |
1388 | printk(KERN_ERR "HVCS: registration " | 1556 | printk(KERN_ERR "HVCS: registration as a tty driver failed.\n"); |
1389 | " as a tty driver failed.\n"); | 1557 | rc = -EIO; |
1390 | hvcs_free_index_list(); | 1558 | goto register_fail; |
1391 | put_tty_driver(hvcs_tty_driver); | ||
1392 | return -EIO; | ||
1393 | } | 1559 | } |
1394 | 1560 | ||
1395 | hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); | 1561 | hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); |
1396 | if (!hvcs_pi_buff) { | 1562 | if (!hvcs_pi_buff) { |
1397 | tty_unregister_driver(hvcs_tty_driver); | 1563 | rc = -ENOMEM; |
1398 | hvcs_free_index_list(); | 1564 | goto buff_alloc_fail; |
1399 | put_tty_driver(hvcs_tty_driver); | ||
1400 | return -ENOMEM; | ||
1401 | } | 1565 | } |
1402 | 1566 | ||
1403 | hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); | 1567 | hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); |
1404 | if (IS_ERR(hvcs_task)) { | 1568 | if (IS_ERR(hvcs_task)) { |
1405 | printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); | 1569 | printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); |
1406 | kfree(hvcs_pi_buff); | 1570 | rc = -EIO; |
1407 | tty_unregister_driver(hvcs_tty_driver); | 1571 | goto kthread_fail; |
1408 | hvcs_free_index_list(); | ||
1409 | put_tty_driver(hvcs_tty_driver); | ||
1410 | return -EIO; | ||
1411 | } | 1572 | } |
1412 | 1573 | ||
1413 | rc = vio_register_driver(&hvcs_vio_driver); | 1574 | rc = vio_register_driver(&hvcs_vio_driver); |
1575 | if (rc) { | ||
1576 | printk(KERN_ERR "HVCS: can't register vio driver\n"); | ||
1577 | goto vio_fail; | ||
1578 | } | ||
1414 | 1579 | ||
1415 | /* | 1580 | /* |
1416 | * This needs to be done AFTER the vio_register_driver() call or else | 1581 | * This needs to be done AFTER the vio_register_driver() call or else |
1417 | * the kobjects won't be initialized properly. | 1582 | * the kobjects won't be initialized properly. |
1418 | */ | 1583 | */ |
1419 | hvcs_create_driver_attrs(); | 1584 | rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan); |
1585 | if (rc) { | ||
1586 | printk(KERN_ERR "HVCS: sysfs attr create failed\n"); | ||
1587 | goto attr_fail; | ||
1588 | } | ||
1420 | 1589 | ||
1421 | printk(KERN_INFO "HVCS: driver module inserted.\n"); | 1590 | printk(KERN_INFO "HVCS: driver module inserted.\n"); |
1422 | 1591 | ||
1592 | return 0; | ||
1593 | |||
1594 | attr_fail: | ||
1595 | vio_unregister_driver(&hvcs_vio_driver); | ||
1596 | vio_fail: | ||
1597 | kthread_stop(hvcs_task); | ||
1598 | kthread_fail: | ||
1599 | kfree(hvcs_pi_buff); | ||
1600 | buff_alloc_fail: | ||
1601 | tty_unregister_driver(hvcs_tty_driver); | ||
1602 | register_fail: | ||
1603 | hvcs_free_index_list(); | ||
1604 | index_fail: | ||
1605 | put_tty_driver(hvcs_tty_driver); | ||
1606 | hvcs_tty_driver = NULL; | ||
1423 | return rc; | 1607 | return rc; |
1424 | } | 1608 | } |
1425 | 1609 | ||
@@ -1441,7 +1625,7 @@ static void __exit hvcs_module_exit(void) | |||
1441 | hvcs_pi_buff = NULL; | 1625 | hvcs_pi_buff = NULL; |
1442 | spin_unlock(&hvcs_pi_lock); | 1626 | spin_unlock(&hvcs_pi_lock); |
1443 | 1627 | ||
1444 | hvcs_remove_driver_attrs(); | 1628 | driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan); |
1445 | 1629 | ||
1446 | vio_unregister_driver(&hvcs_vio_driver); | 1630 | vio_unregister_driver(&hvcs_vio_driver); |
1447 | 1631 | ||
@@ -1456,191 +1640,3 @@ static void __exit hvcs_module_exit(void) | |||
1456 | 1640 | ||
1457 | module_init(hvcs_module_init); | 1641 | module_init(hvcs_module_init); |
1458 | module_exit(hvcs_module_exit); | 1642 | module_exit(hvcs_module_exit); |
1459 | |||
1460 | static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) | ||
1461 | { | ||
1462 | return viod->dev.driver_data; | ||
1463 | } | ||
1464 | /* The sysfs interface for the driver and devices */ | ||
1465 | |||
1466 | static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1467 | { | ||
1468 | struct vio_dev *viod = to_vio_dev(dev); | ||
1469 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1470 | unsigned long flags; | ||
1471 | int retval; | ||
1472 | |||
1473 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1474 | retval = sprintf(buf, "%X\n", hvcsd->p_unit_address); | ||
1475 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1476 | return retval; | ||
1477 | } | ||
1478 | static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); | ||
1479 | |||
1480 | static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1481 | { | ||
1482 | struct vio_dev *viod = to_vio_dev(dev); | ||
1483 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1484 | unsigned long flags; | ||
1485 | int retval; | ||
1486 | |||
1487 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1488 | retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); | ||
1489 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1490 | return retval; | ||
1491 | } | ||
1492 | static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); | ||
1493 | |||
1494 | static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, | ||
1495 | size_t count) | ||
1496 | { | ||
1497 | /* | ||
1498 | * Don't need this feature at the present time because firmware doesn't | ||
1499 | * yet support multiple partners. | ||
1500 | */ | ||
1501 | printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n"); | ||
1502 | return -EPERM; | ||
1503 | } | ||
1504 | |||
1505 | static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1506 | { | ||
1507 | struct vio_dev *viod = to_vio_dev(dev); | ||
1508 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1509 | unsigned long flags; | ||
1510 | int retval; | ||
1511 | |||
1512 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1513 | retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]); | ||
1514 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1515 | return retval; | ||
1516 | } | ||
1517 | |||
1518 | static DEVICE_ATTR(current_vty, | ||
1519 | S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); | ||
1520 | |||
1521 | static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, | ||
1522 | size_t count) | ||
1523 | { | ||
1524 | struct vio_dev *viod = to_vio_dev(dev); | ||
1525 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1526 | unsigned long flags; | ||
1527 | |||
1528 | /* writing a '0' to this sysfs entry will result in the disconnect. */ | ||
1529 | if (simple_strtol(buf, NULL, 0) != 0) | ||
1530 | return -EINVAL; | ||
1531 | |||
1532 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1533 | |||
1534 | if (hvcsd->open_count > 0) { | ||
1535 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1536 | printk(KERN_INFO "HVCS: vterm state unchanged. " | ||
1537 | "The hvcs device node is still in use.\n"); | ||
1538 | return -EPERM; | ||
1539 | } | ||
1540 | |||
1541 | if (hvcsd->connected == 0) { | ||
1542 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1543 | printk(KERN_INFO "HVCS: vterm state unchanged. The" | ||
1544 | " vty-server is not connected to a vty.\n"); | ||
1545 | return -EPERM; | ||
1546 | } | ||
1547 | |||
1548 | hvcs_partner_free(hvcsd); | ||
1549 | printk(KERN_INFO "HVCS: Closed vty-server@%X and" | ||
1550 | " partner vty@%X:%d connection.\n", | ||
1551 | hvcsd->vdev->unit_address, | ||
1552 | hvcsd->p_unit_address, | ||
1553 | (uint32_t)hvcsd->p_partition_ID); | ||
1554 | |||
1555 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1556 | return count; | ||
1557 | } | ||
1558 | |||
1559 | static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1560 | { | ||
1561 | struct vio_dev *viod = to_vio_dev(dev); | ||
1562 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1563 | unsigned long flags; | ||
1564 | int retval; | ||
1565 | |||
1566 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1567 | retval = sprintf(buf, "%d\n", hvcsd->connected); | ||
1568 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1569 | return retval; | ||
1570 | } | ||
1571 | static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, | ||
1572 | hvcs_vterm_state_show, hvcs_vterm_state_store); | ||
1573 | |||
1574 | static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1575 | { | ||
1576 | struct vio_dev *viod = to_vio_dev(dev); | ||
1577 | struct hvcs_struct *hvcsd = from_vio_dev(viod); | ||
1578 | unsigned long flags; | ||
1579 | int retval; | ||
1580 | |||
1581 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
1582 | retval = sprintf(buf, "%d\n", hvcsd->index); | ||
1583 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
1584 | return retval; | ||
1585 | } | ||
1586 | |||
1587 | static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL); | ||
1588 | |||
1589 | static struct attribute *hvcs_attrs[] = { | ||
1590 | &dev_attr_partner_vtys.attr, | ||
1591 | &dev_attr_partner_clcs.attr, | ||
1592 | &dev_attr_current_vty.attr, | ||
1593 | &dev_attr_vterm_state.attr, | ||
1594 | &dev_attr_index.attr, | ||
1595 | NULL, | ||
1596 | }; | ||
1597 | |||
1598 | static struct attribute_group hvcs_attr_group = { | ||
1599 | .attrs = hvcs_attrs, | ||
1600 | }; | ||
1601 | |||
1602 | static void hvcs_create_device_attrs(struct hvcs_struct *hvcsd) | ||
1603 | { | ||
1604 | struct vio_dev *vdev = hvcsd->vdev; | ||
1605 | sysfs_create_group(&vdev->dev.kobj, &hvcs_attr_group); | ||
1606 | } | ||
1607 | |||
1608 | static void hvcs_remove_device_attrs(struct vio_dev *vdev) | ||
1609 | { | ||
1610 | sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group); | ||
1611 | } | ||
1612 | |||
1613 | static ssize_t hvcs_rescan_show(struct device_driver *ddp, char *buf) | ||
1614 | { | ||
1615 | /* A 1 means it is updating, a 0 means it is done updating */ | ||
1616 | return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status); | ||
1617 | } | ||
1618 | |||
1619 | static ssize_t hvcs_rescan_store(struct device_driver *ddp, const char * buf, | ||
1620 | size_t count) | ||
1621 | { | ||
1622 | if ((simple_strtol(buf, NULL, 0) != 1) | ||
1623 | && (hvcs_rescan_status != 0)) | ||
1624 | return -EINVAL; | ||
1625 | |||
1626 | hvcs_rescan_status = 1; | ||
1627 | printk(KERN_INFO "HVCS: rescanning partner info for all" | ||
1628 | " vty-servers.\n"); | ||
1629 | hvcs_rescan_devices_list(); | ||
1630 | hvcs_rescan_status = 0; | ||
1631 | return count; | ||
1632 | } | ||
1633 | static DRIVER_ATTR(rescan, | ||
1634 | S_IRUGO | S_IWUSR, hvcs_rescan_show, hvcs_rescan_store); | ||
1635 | |||
1636 | static void hvcs_create_driver_attrs(void) | ||
1637 | { | ||
1638 | struct device_driver *driverfs = &(hvcs_vio_driver.driver); | ||
1639 | driver_create_file(driverfs, &driver_attr_rescan); | ||
1640 | } | ||
1641 | |||
1642 | static void hvcs_remove_driver_attrs(void) | ||
1643 | { | ||
1644 | struct device_driver *driverfs = &(hvcs_vio_driver.driver); | ||
1645 | driver_remove_file(driverfs, &driver_attr_rescan); | ||
1646 | } | ||