linux/drivers/staging/dgnc/dgnc_sysfs.c
<<
>>
Prefs
   1/*
   2 * Copyright 2004 Digi International (www.digi.com)
   3 *      Scott H Kilau <Scott_Kilau at digi dot com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2, or (at your option)
   8 * any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
  12 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  13 * PURPOSE.  See the GNU General Public License for more details.
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/ctype.h>
  19#include <linux/string.h>
  20#include <linux/serial_reg.h>
  21#include <linux/device.h>
  22#include <linux/pci.h>
  23#include <linux/kdev_t.h>
  24
  25#include "dgnc_driver.h"
  26#include "dgnc_mgmt.h"
  27
  28static ssize_t dgnc_driver_version_show(struct device_driver *ddp, char *buf)
  29{
  30        return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
  31}
  32static DRIVER_ATTR(version, S_IRUSR, dgnc_driver_version_show, NULL);
  33
  34static ssize_t dgnc_driver_boards_show(struct device_driver *ddp, char *buf)
  35{
  36        return snprintf(buf, PAGE_SIZE, "%d\n", dgnc_NumBoards);
  37}
  38static DRIVER_ATTR(boards, S_IRUSR, dgnc_driver_boards_show, NULL);
  39
  40static ssize_t dgnc_driver_maxboards_show(struct device_driver *ddp, char *buf)
  41{
  42        return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
  43}
  44static DRIVER_ATTR(maxboards, S_IRUSR, dgnc_driver_maxboards_show, NULL);
  45
  46static ssize_t dgnc_driver_pollrate_show(struct device_driver *ddp, char *buf)
  47{
  48        return snprintf(buf, PAGE_SIZE, "%dms\n", dgnc_poll_tick);
  49}
  50
  51static ssize_t dgnc_driver_pollrate_store(struct device_driver *ddp,
  52                                          const char *buf, size_t count)
  53{
  54        unsigned long flags;
  55        int tick;
  56        int ret;
  57
  58        ret = sscanf(buf, "%d\n", &tick);
  59        if (ret != 1)
  60                return -EINVAL;
  61
  62        spin_lock_irqsave(&dgnc_poll_lock, flags);
  63        dgnc_poll_tick = tick;
  64        spin_unlock_irqrestore(&dgnc_poll_lock, flags);
  65
  66        return count;
  67}
  68static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgnc_driver_pollrate_show,
  69                   dgnc_driver_pollrate_store);
  70
  71void dgnc_create_driver_sysfiles(struct pci_driver *dgnc_driver)
  72{
  73        int rc = 0;
  74        struct device_driver *driverfs = &dgnc_driver->driver;
  75
  76        rc |= driver_create_file(driverfs, &driver_attr_version);
  77        rc |= driver_create_file(driverfs, &driver_attr_boards);
  78        rc |= driver_create_file(driverfs, &driver_attr_maxboards);
  79        rc |= driver_create_file(driverfs, &driver_attr_pollrate);
  80        if (rc)
  81                pr_err("DGNC: sysfs driver_create_file failed!\n");
  82}
  83
  84void dgnc_remove_driver_sysfiles(struct pci_driver *dgnc_driver)
  85{
  86        struct device_driver *driverfs = &dgnc_driver->driver;
  87
  88        driver_remove_file(driverfs, &driver_attr_version);
  89        driver_remove_file(driverfs, &driver_attr_boards);
  90        driver_remove_file(driverfs, &driver_attr_maxboards);
  91        driver_remove_file(driverfs, &driver_attr_pollrate);
  92}
  93
  94#define DGNC_VERIFY_BOARD(p, bd)                                \
  95        do {                                                    \
  96                if (!p)                                         \
  97                        return 0;                               \
  98                                                                \
  99                bd = dev_get_drvdata(p);                        \
 100                if (!bd || bd->magic != DGNC_BOARD_MAGIC)       \
 101                        return 0;                               \
 102                if (bd->state != BOARD_READY)                   \
 103                        return 0;                               \
 104        } while (0)
 105
 106static ssize_t dgnc_vpd_show(struct device *p, struct device_attribute *attr,
 107                             char *buf)
 108{
 109        struct dgnc_board *bd;
 110        int count = 0;
 111        int i = 0;
 112
 113        DGNC_VERIFY_BOARD(p, bd);
 114
 115        count += sprintf(buf + count,
 116                "\n      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
 117        for (i = 0; i < 0x40 * 2; i++) {
 118                if (!(i % 16))
 119                        count += sprintf(buf + count, "\n%04X ", i * 2);
 120                count += sprintf(buf + count, "%02X ", bd->vpd[i]);
 121        }
 122        count += sprintf(buf + count, "\n");
 123
 124        return count;
 125}
 126static DEVICE_ATTR(vpd, S_IRUSR, dgnc_vpd_show, NULL);
 127
 128static ssize_t dgnc_serial_number_show(struct device *p,
 129                                       struct device_attribute *attr, char *buf)
 130{
 131        struct dgnc_board *bd;
 132        int count = 0;
 133
 134        DGNC_VERIFY_BOARD(p, bd);
 135
 136        if (bd->serial_num[0] == '\0')
 137                count += sprintf(buf + count, "<UNKNOWN>\n");
 138        else
 139                count += sprintf(buf + count, "%s\n", bd->serial_num);
 140
 141        return count;
 142}
 143static DEVICE_ATTR(serial_number, S_IRUSR, dgnc_serial_number_show, NULL);
 144
 145static ssize_t dgnc_ports_state_show(struct device *p,
 146                                     struct device_attribute *attr, char *buf)
 147{
 148        struct dgnc_board *bd;
 149        int count = 0;
 150        int i = 0;
 151
 152        DGNC_VERIFY_BOARD(p, bd);
 153
 154        for (i = 0; i < bd->nasync; i++) {
 155                count += snprintf(buf + count, PAGE_SIZE - count,
 156                        "%d %s\n", bd->channels[i]->ch_portnum,
 157                        bd->channels[i]->ch_open_count ? "Open" : "Closed");
 158        }
 159        return count;
 160}
 161static DEVICE_ATTR(ports_state, S_IRUSR, dgnc_ports_state_show, NULL);
 162
 163static ssize_t dgnc_ports_baud_show(struct device *p,
 164                                    struct device_attribute *attr, char *buf)
 165{
 166        struct dgnc_board *bd;
 167        int count = 0;
 168        int i = 0;
 169
 170        DGNC_VERIFY_BOARD(p, bd);
 171
 172        for (i = 0; i < bd->nasync; i++) {
 173                count +=  snprintf(buf + count, PAGE_SIZE - count,
 174                        "%d %d\n", bd->channels[i]->ch_portnum,
 175                        bd->channels[i]->ch_old_baud);
 176        }
 177        return count;
 178}
 179static DEVICE_ATTR(ports_baud, S_IRUSR, dgnc_ports_baud_show, NULL);
 180
 181static ssize_t dgnc_ports_msignals_show(struct device *p,
 182                                        struct device_attribute *attr,
 183                                        char *buf)
 184{
 185        struct dgnc_board *bd;
 186        int count = 0;
 187        int i = 0;
 188
 189        DGNC_VERIFY_BOARD(p, bd);
 190
 191        for (i = 0; i < bd->nasync; i++) {
 192                if (bd->channels[i]->ch_open_count) {
 193                        count += snprintf(buf + count, PAGE_SIZE - count,
 194                                "%d %s %s %s %s %s %s\n",
 195                                bd->channels[i]->ch_portnum,
 196                                (bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
 197                                (bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
 198                                (bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
 199                                (bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
 200                                (bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
 201                                (bd->channels[i]->ch_mistat & UART_MSR_RI)  ? "RI"  : "");
 202                } else {
 203                        count += snprintf(buf + count, PAGE_SIZE - count,
 204                                "%d\n", bd->channels[i]->ch_portnum);
 205                }
 206        }
 207        return count;
 208}
 209static DEVICE_ATTR(ports_msignals, S_IRUSR, dgnc_ports_msignals_show, NULL);
 210
 211static ssize_t dgnc_ports_iflag_show(struct device *p,
 212                                     struct device_attribute *attr, char *buf)
 213{
 214        struct dgnc_board *bd;
 215        int count = 0;
 216        int i = 0;
 217
 218        DGNC_VERIFY_BOARD(p, bd);
 219
 220        for (i = 0; i < bd->nasync; i++) {
 221                count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
 222                        bd->channels[i]->ch_portnum,
 223                        bd->channels[i]->ch_c_iflag);
 224        }
 225        return count;
 226}
 227static DEVICE_ATTR(ports_iflag, S_IRUSR, dgnc_ports_iflag_show, NULL);
 228
 229static ssize_t dgnc_ports_cflag_show(struct device *p,
 230                                     struct device_attribute *attr, char *buf)
 231{
 232        struct dgnc_board *bd;
 233        int count = 0;
 234        int i = 0;
 235
 236        DGNC_VERIFY_BOARD(p, bd);
 237
 238        for (i = 0; i < bd->nasync; i++) {
 239                count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
 240                        bd->channels[i]->ch_portnum,
 241                        bd->channels[i]->ch_c_cflag);
 242        }
 243        return count;
 244}
 245static DEVICE_ATTR(ports_cflag, S_IRUSR, dgnc_ports_cflag_show, NULL);
 246
 247static ssize_t dgnc_ports_oflag_show(struct device *p,
 248                                     struct device_attribute *attr, char *buf)
 249{
 250        struct dgnc_board *bd;
 251        int count = 0;
 252        int i = 0;
 253
 254        DGNC_VERIFY_BOARD(p, bd);
 255
 256        for (i = 0; i < bd->nasync; i++) {
 257                count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
 258                        bd->channels[i]->ch_portnum,
 259                        bd->channels[i]->ch_c_oflag);
 260        }
 261        return count;
 262}
 263static DEVICE_ATTR(ports_oflag, S_IRUSR, dgnc_ports_oflag_show, NULL);
 264
 265static ssize_t dgnc_ports_lflag_show(struct device *p,
 266                                     struct device_attribute *attr, char *buf)
 267{
 268        struct dgnc_board *bd;
 269        int count = 0;
 270        int i = 0;
 271
 272        DGNC_VERIFY_BOARD(p, bd);
 273
 274        for (i = 0; i < bd->nasync; i++) {
 275                count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
 276                        bd->channels[i]->ch_portnum,
 277                        bd->channels[i]->ch_c_lflag);
 278        }
 279        return count;
 280}
 281static DEVICE_ATTR(ports_lflag, S_IRUSR, dgnc_ports_lflag_show, NULL);
 282
 283static ssize_t dgnc_ports_digi_flag_show(struct device *p,
 284                                         struct device_attribute *attr,
 285                                         char *buf)
 286{
 287        struct dgnc_board *bd;
 288        int count = 0;
 289        int i = 0;
 290
 291        DGNC_VERIFY_BOARD(p, bd);
 292
 293        for (i = 0; i < bd->nasync; i++) {
 294                count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
 295                        bd->channels[i]->ch_portnum,
 296                        bd->channels[i]->ch_digi.digi_flags);
 297        }
 298        return count;
 299}
 300static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgnc_ports_digi_flag_show, NULL);
 301
 302static ssize_t dgnc_ports_rxcount_show(struct device *p,
 303                                       struct device_attribute *attr, char *buf)
 304{
 305        struct dgnc_board *bd;
 306        int count = 0;
 307        int i = 0;
 308
 309        DGNC_VERIFY_BOARD(p, bd);
 310
 311        for (i = 0; i < bd->nasync; i++) {
 312                count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
 313                        bd->channels[i]->ch_portnum,
 314                        bd->channels[i]->ch_rxcount);
 315        }
 316        return count;
 317}
 318static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgnc_ports_rxcount_show, NULL);
 319
 320static ssize_t dgnc_ports_txcount_show(struct device *p,
 321                                       struct device_attribute *attr, char *buf)
 322{
 323        struct dgnc_board *bd;
 324        int count = 0;
 325        int i = 0;
 326
 327        DGNC_VERIFY_BOARD(p, bd);
 328
 329        for (i = 0; i < bd->nasync; i++) {
 330                count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
 331                        bd->channels[i]->ch_portnum,
 332                        bd->channels[i]->ch_txcount);
 333        }
 334        return count;
 335}
 336static DEVICE_ATTR(ports_txcount, S_IRUSR, dgnc_ports_txcount_show, NULL);
 337
 338/* this function creates the sys files that will export each signal status
 339 * to sysfs each value will be put in a separate filename
 340 */
 341void dgnc_create_ports_sysfiles(struct dgnc_board *bd)
 342{
 343        int rc = 0;
 344
 345        dev_set_drvdata(&bd->pdev->dev, bd);
 346        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_state);
 347        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_baud);
 348        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_msignals);
 349        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_iflag);
 350        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_cflag);
 351        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_oflag);
 352        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_lflag);
 353        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_digi_flag);
 354        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_rxcount);
 355        rc |= device_create_file(&bd->pdev->dev, &dev_attr_ports_txcount);
 356        rc |= device_create_file(&bd->pdev->dev, &dev_attr_vpd);
 357        rc |= device_create_file(&bd->pdev->dev, &dev_attr_serial_number);
 358        if (rc)
 359                dev_err(&bd->pdev->dev, "dgnc: sysfs device_create_file failed!\n");
 360}
 361
 362/* removes all the sys files created for that port */
 363void dgnc_remove_ports_sysfiles(struct dgnc_board *bd)
 364{
 365        device_remove_file(&bd->pdev->dev, &dev_attr_ports_state);
 366        device_remove_file(&bd->pdev->dev, &dev_attr_ports_baud);
 367        device_remove_file(&bd->pdev->dev, &dev_attr_ports_msignals);
 368        device_remove_file(&bd->pdev->dev, &dev_attr_ports_iflag);
 369        device_remove_file(&bd->pdev->dev, &dev_attr_ports_cflag);
 370        device_remove_file(&bd->pdev->dev, &dev_attr_ports_oflag);
 371        device_remove_file(&bd->pdev->dev, &dev_attr_ports_lflag);
 372        device_remove_file(&bd->pdev->dev, &dev_attr_ports_digi_flag);
 373        device_remove_file(&bd->pdev->dev, &dev_attr_ports_rxcount);
 374        device_remove_file(&bd->pdev->dev, &dev_attr_ports_txcount);
 375        device_remove_file(&bd->pdev->dev, &dev_attr_vpd);
 376        device_remove_file(&bd->pdev->dev, &dev_attr_serial_number);
 377}
 378
 379static ssize_t dgnc_tty_state_show(struct device *d,
 380                                   struct device_attribute *attr, char *buf)
 381{
 382        struct dgnc_board *bd;
 383        struct channel_t *ch;
 384        struct un_t *un;
 385
 386        if (!d)
 387                return 0;
 388        un = dev_get_drvdata(d);
 389        if (!un || un->magic != DGNC_UNIT_MAGIC)
 390                return 0;
 391        ch = un->un_ch;
 392        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 393                return 0;
 394        bd = ch->ch_bd;
 395        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 396                return 0;
 397        if (bd->state != BOARD_READY)
 398                return 0;
 399
 400        return snprintf(buf, PAGE_SIZE, "%s",
 401                        un->un_open_count ? "Open" : "Closed");
 402}
 403static DEVICE_ATTR(state, S_IRUSR, dgnc_tty_state_show, NULL);
 404
 405static ssize_t dgnc_tty_baud_show(struct device *d,
 406                                  struct device_attribute *attr, char *buf)
 407{
 408        struct dgnc_board *bd;
 409        struct channel_t *ch;
 410        struct un_t *un;
 411
 412        if (!d)
 413                return 0;
 414        un = dev_get_drvdata(d);
 415        if (!un || un->magic != DGNC_UNIT_MAGIC)
 416                return 0;
 417        ch = un->un_ch;
 418        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 419                return 0;
 420        bd = ch->ch_bd;
 421        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 422                return 0;
 423        if (bd->state != BOARD_READY)
 424                return 0;
 425
 426        return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_old_baud);
 427}
 428static DEVICE_ATTR(baud, S_IRUSR, dgnc_tty_baud_show, NULL);
 429
 430static ssize_t dgnc_tty_msignals_show(struct device *d,
 431                                      struct device_attribute *attr, char *buf)
 432{
 433        struct dgnc_board *bd;
 434        struct channel_t *ch;
 435        struct un_t *un;
 436
 437        if (!d)
 438                return 0;
 439        un = dev_get_drvdata(d);
 440        if (!un || un->magic != DGNC_UNIT_MAGIC)
 441                return 0;
 442        ch = un->un_ch;
 443        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 444                return 0;
 445        bd = ch->ch_bd;
 446        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 447                return 0;
 448        if (bd->state != BOARD_READY)
 449                return 0;
 450
 451        if (ch->ch_open_count) {
 452                return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
 453                        (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
 454                        (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
 455                        (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
 456                        (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
 457                        (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
 458                        (ch->ch_mistat & UART_MSR_RI)  ? "RI"  : "");
 459        }
 460        return 0;
 461}
 462static DEVICE_ATTR(msignals, S_IRUSR, dgnc_tty_msignals_show, NULL);
 463
 464static ssize_t dgnc_tty_iflag_show(struct device *d,
 465                                   struct device_attribute *attr, char *buf)
 466{
 467        struct dgnc_board *bd;
 468        struct channel_t *ch;
 469        struct un_t *un;
 470
 471        if (!d)
 472                return 0;
 473        un = dev_get_drvdata(d);
 474        if (!un || un->magic != DGNC_UNIT_MAGIC)
 475                return 0;
 476        ch = un->un_ch;
 477        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 478                return 0;
 479        bd = ch->ch_bd;
 480        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 481                return 0;
 482        if (bd->state != BOARD_READY)
 483                return 0;
 484
 485        return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
 486}
 487static DEVICE_ATTR(iflag, S_IRUSR, dgnc_tty_iflag_show, NULL);
 488
 489static ssize_t dgnc_tty_cflag_show(struct device *d,
 490                                   struct device_attribute *attr, char *buf)
 491{
 492        struct dgnc_board *bd;
 493        struct channel_t *ch;
 494        struct un_t *un;
 495
 496        if (!d)
 497                return 0;
 498        un = dev_get_drvdata(d);
 499        if (!un || un->magic != DGNC_UNIT_MAGIC)
 500                return 0;
 501        ch = un->un_ch;
 502        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 503                return 0;
 504        bd = ch->ch_bd;
 505        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 506                return 0;
 507        if (bd->state != BOARD_READY)
 508                return 0;
 509
 510        return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
 511}
 512static DEVICE_ATTR(cflag, S_IRUSR, dgnc_tty_cflag_show, NULL);
 513
 514static ssize_t dgnc_tty_oflag_show(struct device *d,
 515                                   struct device_attribute *attr, char *buf)
 516{
 517        struct dgnc_board *bd;
 518        struct channel_t *ch;
 519        struct un_t *un;
 520
 521        if (!d)
 522                return 0;
 523        un = dev_get_drvdata(d);
 524        if (!un || un->magic != DGNC_UNIT_MAGIC)
 525                return 0;
 526        ch = un->un_ch;
 527        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 528                return 0;
 529        bd = ch->ch_bd;
 530        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 531                return 0;
 532        if (bd->state != BOARD_READY)
 533                return 0;
 534
 535        return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
 536}
 537static DEVICE_ATTR(oflag, S_IRUSR, dgnc_tty_oflag_show, NULL);
 538
 539static ssize_t dgnc_tty_lflag_show(struct device *d,
 540                                   struct device_attribute *attr, char *buf)
 541{
 542        struct dgnc_board *bd;
 543        struct channel_t *ch;
 544        struct un_t *un;
 545
 546        if (!d)
 547                return 0;
 548        un = dev_get_drvdata(d);
 549        if (!un || un->magic != DGNC_UNIT_MAGIC)
 550                return 0;
 551        ch = un->un_ch;
 552        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 553                return 0;
 554        bd = ch->ch_bd;
 555        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 556                return 0;
 557        if (bd->state != BOARD_READY)
 558                return 0;
 559
 560        return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
 561}
 562static DEVICE_ATTR(lflag, S_IRUSR, dgnc_tty_lflag_show, NULL);
 563
 564static ssize_t dgnc_tty_digi_flag_show(struct device *d,
 565                                       struct device_attribute *attr, char *buf)
 566{
 567        struct dgnc_board *bd;
 568        struct channel_t *ch;
 569        struct un_t *un;
 570
 571        if (!d)
 572                return 0;
 573        un = dev_get_drvdata(d);
 574        if (!un || un->magic != DGNC_UNIT_MAGIC)
 575                return 0;
 576        ch = un->un_ch;
 577        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 578                return 0;
 579        bd = ch->ch_bd;
 580        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 581                return 0;
 582        if (bd->state != BOARD_READY)
 583                return 0;
 584
 585        return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
 586}
 587static DEVICE_ATTR(digi_flag, S_IRUSR, dgnc_tty_digi_flag_show, NULL);
 588
 589static ssize_t dgnc_tty_rxcount_show(struct device *d,
 590                                     struct device_attribute *attr, char *buf)
 591{
 592        struct dgnc_board *bd;
 593        struct channel_t *ch;
 594        struct un_t *un;
 595
 596        if (!d)
 597                return 0;
 598        un = dev_get_drvdata(d);
 599        if (!un || un->magic != DGNC_UNIT_MAGIC)
 600                return 0;
 601        ch = un->un_ch;
 602        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 603                return 0;
 604        bd = ch->ch_bd;
 605        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 606                return 0;
 607        if (bd->state != BOARD_READY)
 608                return 0;
 609
 610        return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
 611}
 612static DEVICE_ATTR(rxcount, S_IRUSR, dgnc_tty_rxcount_show, NULL);
 613
 614static ssize_t dgnc_tty_txcount_show(struct device *d,
 615                                     struct device_attribute *attr, char *buf)
 616{
 617        struct dgnc_board *bd;
 618        struct channel_t *ch;
 619        struct un_t *un;
 620
 621        if (!d)
 622                return 0;
 623        un = dev_get_drvdata(d);
 624        if (!un || un->magic != DGNC_UNIT_MAGIC)
 625                return 0;
 626        ch = un->un_ch;
 627        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 628                return 0;
 629        bd = ch->ch_bd;
 630        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 631                return 0;
 632        if (bd->state != BOARD_READY)
 633                return 0;
 634
 635        return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
 636}
 637static DEVICE_ATTR(txcount, S_IRUSR, dgnc_tty_txcount_show, NULL);
 638
 639static ssize_t dgnc_tty_name_show(struct device *d,
 640                                  struct device_attribute *attr, char *buf)
 641{
 642        struct dgnc_board *bd;
 643        struct channel_t *ch;
 644        struct un_t *un;
 645
 646        if (!d)
 647                return 0;
 648        un = dev_get_drvdata(d);
 649        if (!un || un->magic != DGNC_UNIT_MAGIC)
 650                return 0;
 651        ch = un->un_ch;
 652        if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 653                return 0;
 654        bd = ch->ch_bd;
 655        if (!bd || bd->magic != DGNC_BOARD_MAGIC)
 656                return 0;
 657        if (bd->state != BOARD_READY)
 658                return 0;
 659
 660        return snprintf(buf, PAGE_SIZE, "%sn%d%c\n",
 661                (un->un_type == DGNC_PRINT) ? "pr" : "tty",
 662                bd->boardnum + 1, 'a' + ch->ch_portnum);
 663}
 664static DEVICE_ATTR(custom_name, S_IRUSR, dgnc_tty_name_show, NULL);
 665
 666static struct attribute *dgnc_sysfs_tty_entries[] = {
 667        &dev_attr_state.attr,
 668        &dev_attr_baud.attr,
 669        &dev_attr_msignals.attr,
 670        &dev_attr_iflag.attr,
 671        &dev_attr_cflag.attr,
 672        &dev_attr_oflag.attr,
 673        &dev_attr_lflag.attr,
 674        &dev_attr_digi_flag.attr,
 675        &dev_attr_rxcount.attr,
 676        &dev_attr_txcount.attr,
 677        &dev_attr_custom_name.attr,
 678        NULL
 679};
 680
 681static struct attribute_group dgnc_tty_attribute_group = {
 682        .name = NULL,
 683        .attrs = dgnc_sysfs_tty_entries,
 684};
 685
 686void dgnc_create_tty_sysfs(struct un_t *un, struct device *c)
 687{
 688        int ret;
 689
 690        ret = sysfs_create_group(&c->kobj, &dgnc_tty_attribute_group);
 691        if (ret) {
 692                dev_err(c, "dgnc: failed to create sysfs tty device attributes.\n");
 693                sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);
 694                return;
 695        }
 696
 697        dev_set_drvdata(c, un);
 698}
 699
 700void dgnc_remove_tty_sysfs(struct device *c)
 701{
 702        sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);
 703}
 704
 705