/* * Copyright 2004 Digi International (www.digi.com) * Scott H Kilau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! * * This is shared code between Digi's CVS archive and the * Linux Kernel sources. * Changing the source just for reformatting needlessly breaks * our CVS diff history. * * Send any bug fixes/changes to: Eng.Linux at digi dot com. * Thank you. * * * * $Id: dgap_sysfs.c,v 1.1 2009/10/23 14:01:57 markh Exp $ */ #include #include #include #include #include #include #include #include #include "dgap_driver.h" #include "dgap_conf.h" #include "dgap_parse.h" static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART); } static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL); static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", dgap_NumBoards); } static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL); static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS); } static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL); static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp, char *buf) { return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter); } static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL); static ssize_t dgap_driver_state_show(struct device_driver *ddp, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", dgap_driver_state_text[dgap_driver_state]); } static DRIVER_ATTR(state, S_IRUSR, dgap_driver_state_show, NULL); static ssize_t dgap_driver_debug_show(struct device_driver *ddp, char *buf) { return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_debug); } static ssize_t dgap_driver_debug_store(struct device_driver *ddp, const char *buf, size_t count) { sscanf(buf, "0x%x\n", &dgap_debug); return count; } static DRIVER_ATTR(debug, (S_IRUSR | S_IWUSR), dgap_driver_debug_show, dgap_driver_debug_store); static ssize_t dgap_driver_rawreadok_show(struct device_driver *ddp, char *buf) { return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_rawreadok); } static ssize_t dgap_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count) { sscanf(buf, "0x%x\n", &dgap_rawreadok); return count; } static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgap_driver_rawreadok_show, dgap_driver_rawreadok_store); static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf) { return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick); } static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count) { sscanf(buf, "%d\n", &dgap_poll_tick); return count; } static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show, dgap_driver_pollrate_store); void dgap_create_driver_sysfiles(struct pci_driver *dgap_driver) { int rc = 0; struct device_driver *driverfs = &dgap_driver->driver; rc |= driver_create_file(driverfs, &driver_attr_version); rc |= driver_create_file(driverfs, &driver_attr_boards); rc |= driver_create_file(driverfs, &driver_attr_maxboards); rc |= driver_create_file(driverfs, &driver_attr_debug); rc |= driver_create_file(driverfs, &driver_attr_rawreadok); rc |= driver_create_file(driverfs, &driver_attr_pollrate); rc |= driver_create_file(driverfs, &driver_attr_pollcounter); rc |= driver_create_file(driverfs, &driver_attr_state); if (rc) { printk(KERN_ERR "DGAP: sysfs driver_create_file failed!\n"); } } void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver) { struct device_driver *driverfs = &dgap_driver->driver; driver_remove_file(driverfs, &driver_attr_version); driver_remove_file(driverfs, &driver_attr_boards); driver_remove_file(driverfs, &driver_attr_maxboards); driver_remove_file(driverfs, &driver_attr_debug); driver_remove_file(driverfs, &driver_attr_rawreadok); driver_remove_file(driverfs, &driver_attr_pollrate); driver_remove_file(driverfs, &driver_attr_pollcounter); driver_remove_file(driverfs, &driver_attr_state); } #define DGAP_VERIFY_BOARD(p, bd) \ if (!p) \ return (0); \ \ bd = dev_get_drvdata(p); \ if (!bd || bd->magic != DGAP_BOARD_MAGIC) \ return (0); \ if (bd->state != BOARD_READY) \ return (0); \ static ssize_t dgap_ports_state_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %s\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_open_count ? "Open" : "Closed"); } return count; } static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL); static ssize_t dgap_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_baud_info); } return count; } static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL); static ssize_t dgap_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { if (bd->channels[i]->ch_open_count) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum, (bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "", (bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "", (bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "", (bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "", (bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "", (bd->channels[i]->ch_mistat & UART_MSR_RI) ? "RI" : ""); } else { count += snprintf(buf + count, PAGE_SIZE - count, "%d\n", bd->channels[i]->ch_portnum); } } return count; } static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL); static ssize_t dgap_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag); } return count; } static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL); static ssize_t dgap_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag); } return count; } static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL); static ssize_t dgap_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag); } return count; } static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL); static ssize_t dgap_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag); } return count; } static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL); static ssize_t dgap_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags); } return count; } static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL); static ssize_t dgap_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount); } return count; } static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL); static ssize_t dgap_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf) { struct board_t *bd; int count = 0; int i = 0; DGAP_VERIFY_BOARD(p, bd); for (i = 0; i < bd->nasync; i++) { count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount); } return count; } static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL); /* this function creates the sys files that will export each signal status * to sysfs each value will be put in a separate filename */ void dgap_create_ports_sysfiles(struct board_t *bd) { int rc = 0; dev_set_drvdata(&bd->pdev->dev, bd); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount); if (rc) { printk(KERN_ERR "DGAP: sysfs device_create_file failed!\n"); } } /* removes all the sys files created for that port */ void dgap_remove_ports_sysfiles(struct board_t *bd) { device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount); } static ssize_t dgap_tty_state_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed"); } static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL); static ssize_t dgap_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info); } static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL); static ssize_t dgap_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); if (ch->ch_open_count) { return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n", (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "", (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "", (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "", (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "", (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "", (ch->ch_mistat & UART_MSR_RI) ? "RI" : ""); } return 0; } static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL); static ssize_t dgap_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag); } static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL); static ssize_t dgap_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag); } static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL); static ssize_t dgap_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag); } static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL); static ssize_t dgap_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag); } static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL); static ssize_t dgap_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags); } static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL); static ssize_t dgap_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount); } static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL); static ssize_t dgap_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount); } static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL); static ssize_t dgap_tty_name_show(struct device *d, struct device_attribute *attr, char *buf) { struct board_t *bd; struct channel_t *ch; struct un_t *un; int cn; int bn; struct cnode *cptr = NULL; int found = FALSE; int ncount = 0; int starto = 0; int i = 0; if (!d) return (0); un = dev_get_drvdata(d); if (!un || un->magic != DGAP_UNIT_MAGIC) return (0); ch = un->un_ch; if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) return (0); bd = ch->ch_bd; if (!bd || bd->magic != DGAP_BOARD_MAGIC) return (0); if (bd->state != BOARD_READY) return (0); bn = bd->boardnum; cn = ch->ch_portnum; for (cptr = bd->bd_config; cptr; cptr = cptr->next) { if ((cptr->type == BNODE) && ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) || (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) || (cptr->u.board.type == PAPORT8))) { found = TRUE; if (cptr->u.board.v_start) starto = cptr->u.board.start; else starto = 1; } if (cptr->type == TNODE && found == TRUE) { char *ptr1; if (strstr(cptr->u.ttyname, "tty")) { ptr1 = cptr->u.ttyname; ptr1 += 3; } else { ptr1 = cptr->u.ttyname; } for (i = 0; i < dgap_config_get_number_of_ports(bd); i++) { if (cn == i) { return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", (un->un_type == DGAP_PRINT) ? "pr" : "tty", ptr1, i + starto); } } } if (cptr->type == CNODE) { for (i = 0; i < cptr->u.conc.nport; i++) { if (cn == (i + ncount)) { return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", (un->un_type == DGAP_PRINT) ? "pr" : "tty", cptr->u.conc.id, i + (cptr->u.conc.v_start ? cptr->u.conc.start : 1)); } } ncount += cptr->u.conc.nport; } if (cptr->type == MNODE) { for (i = 0; i < cptr->u.module.nport; i++) { if (cn == (i + ncount)) { return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", (un->un_type == DGAP_PRINT) ? "pr" : "tty", cptr->u.module.id, i + (cptr->u.module.v_start ? cptr->u.module.start : 1)); } } ncount += cptr->u.module.nport; } } return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n", (un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn); } static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL); static struct attribute *dgap_sysfs_tty_entries[] = { &dev_attr_state.attr, &dev_attr_baud.attr, &dev_attr_msignals.attr, &dev_attr_iflag.attr, &dev_attr_cflag.attr, &dev_attr_oflag.attr, &dev_attr_lflag.attr, &dev_attr_digi_flag.attr, &dev_attr_rxcount.attr, &dev_attr_txcount.attr, &dev_attr_custom_name.attr, NULL }; static struct attribute_group dgap_tty_attribute_group = { .name = NULL, .attrs = dgap_sysfs_tty_entries, }; void dgap_create_tty_sysfs(struct un_t *un, struct device *c) { int ret; ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group); if (ret) { printk(KERN_ERR "dgap: failed to create sysfs tty device attributes.\n"); sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group); return; } dev_set_drvdata(c, un); } void dgap_remove_tty_sysfs(struct device *c) { sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group); }