2 * Copyright 2004 Digi International (www.digi.com)
3 * Scott H Kilau <Scott_Kilau at digi dot com>
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)
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
22 * This is shared code between Digi's CVS archive and the
23 * Linux Kernel sources.
24 * Changing the source just for reformatting needlessly breaks
25 * our CVS diff history.
27 * Send any bug fixes/changes to: Eng.Linux at digi dot com.
33 #include <linux/kernel.h>
34 #include <linux/module.h>
35 #include <linux/ctype.h>
36 #include <linux/string.h>
37 #include <linux/serial_reg.h>
38 #include <linux/device.h>
39 #include <linux/pci.h>
40 #include <linux/kdev_t.h>
42 #include "dgnc_driver.h"
43 #include "dgnc_mgmt.h"
46 static ssize_t dgnc_driver_version_show(struct device_driver *ddp, char *buf)
48 return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
50 static DRIVER_ATTR(version, S_IRUSR, dgnc_driver_version_show, NULL);
53 static ssize_t dgnc_driver_boards_show(struct device_driver *ddp, char *buf)
55 return snprintf(buf, PAGE_SIZE, "%d\n", dgnc_NumBoards);
57 static DRIVER_ATTR(boards, S_IRUSR, dgnc_driver_boards_show, NULL);
60 static ssize_t dgnc_driver_maxboards_show(struct device_driver *ddp, char *buf)
62 return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
64 static DRIVER_ATTR(maxboards, S_IRUSR, dgnc_driver_maxboards_show, NULL);
66 static ssize_t dgnc_driver_debug_show(struct device_driver *ddp, char *buf)
68 return snprintf(buf, PAGE_SIZE, "0x%x\n", dgnc_debug);
71 static ssize_t dgnc_driver_debug_store(struct device_driver *ddp, const char *buf, size_t count)
75 ret = sscanf(buf, "0x%x\n", &dgnc_debug);
80 static DRIVER_ATTR(debug, (S_IRUSR | S_IWUSR), dgnc_driver_debug_show, dgnc_driver_debug_store);
83 static ssize_t dgnc_driver_rawreadok_show(struct device_driver *ddp, char *buf)
85 return snprintf(buf, PAGE_SIZE, "0x%x\n", dgnc_rawreadok);
88 static ssize_t dgnc_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count)
92 ret = sscanf(buf, "0x%x\n", &dgnc_rawreadok);
97 static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgnc_driver_rawreadok_show, dgnc_driver_rawreadok_store);
100 static ssize_t dgnc_driver_pollrate_show(struct device_driver *ddp, char *buf)
102 return snprintf(buf, PAGE_SIZE, "%dms\n", dgnc_poll_tick);
105 static ssize_t dgnc_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count)
109 ret = sscanf(buf, "%d\n", &dgnc_poll_tick);
114 static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgnc_driver_pollrate_show, dgnc_driver_pollrate_store);
117 void dgnc_create_driver_sysfiles(struct pci_driver *dgnc_driver)
120 struct device_driver *driverfs = &dgnc_driver->driver;
122 rc |= driver_create_file(driverfs, &driver_attr_version);
123 rc |= driver_create_file(driverfs, &driver_attr_boards);
124 rc |= driver_create_file(driverfs, &driver_attr_maxboards);
125 rc |= driver_create_file(driverfs, &driver_attr_debug);
126 rc |= driver_create_file(driverfs, &driver_attr_rawreadok);
127 rc |= driver_create_file(driverfs, &driver_attr_pollrate);
129 printk(KERN_ERR "DGNC: sysfs driver_create_file failed!\n");
134 void dgnc_remove_driver_sysfiles(struct pci_driver *dgnc_driver)
136 struct device_driver *driverfs = &dgnc_driver->driver;
138 driver_remove_file(driverfs, &driver_attr_version);
139 driver_remove_file(driverfs, &driver_attr_boards);
140 driver_remove_file(driverfs, &driver_attr_maxboards);
141 driver_remove_file(driverfs, &driver_attr_debug);
142 driver_remove_file(driverfs, &driver_attr_rawreadok);
143 driver_remove_file(driverfs, &driver_attr_pollrate);
147 #define DGNC_VERIFY_BOARD(p, bd) \
152 bd = dev_get_drvdata(p); \
153 if (!bd || bd->magic != DGNC_BOARD_MAGIC) \
155 if (bd->state != BOARD_READY) \
161 static ssize_t dgnc_vpd_show(struct device *p, struct device_attribute *attr, char *buf)
163 struct dgnc_board *bd;
167 DGNC_VERIFY_BOARD(p, bd);
169 count += sprintf(buf + count, "\n 0 1 2 3 4 5 6 7 8 9 A B C D E F");
170 for (i = 0; i < 0x40 * 2; i++) {
172 count += sprintf(buf + count, "\n%04X ", i * 2);
173 count += sprintf(buf + count, "%02X ", bd->vpd[i]);
175 count += sprintf(buf + count, "\n");
179 static DEVICE_ATTR(vpd, S_IRUSR, dgnc_vpd_show, NULL);
181 static ssize_t dgnc_serial_number_show(struct device *p, struct device_attribute *attr, char *buf)
183 struct dgnc_board *bd;
186 DGNC_VERIFY_BOARD(p, bd);
188 if (bd->serial_num[0] == '\0')
189 count += sprintf(buf + count, "<UNKNOWN>\n");
191 count += sprintf(buf + count, "%s\n", bd->serial_num);
195 static DEVICE_ATTR(serial_number, S_IRUSR, dgnc_serial_number_show, NULL);
198 static ssize_t dgnc_ports_state_show(struct device *p, struct device_attribute *attr, char *buf)
200 struct dgnc_board *bd;
204 DGNC_VERIFY_BOARD(p, bd);
206 for (i = 0; i < bd->nasync; i++) {
207 count += snprintf(buf + count, PAGE_SIZE - count,
208 "%d %s\n", bd->channels[i]->ch_portnum,
209 bd->channels[i]->ch_open_count ? "Open" : "Closed");
213 static DEVICE_ATTR(ports_state, S_IRUSR, dgnc_ports_state_show, NULL);
216 static ssize_t dgnc_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf)
218 struct dgnc_board *bd;
222 DGNC_VERIFY_BOARD(p, bd);
224 for (i = 0; i < bd->nasync; i++) {
225 count += snprintf(buf + count, PAGE_SIZE - count,
226 "%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_old_baud);
230 static DEVICE_ATTR(ports_baud, S_IRUSR, dgnc_ports_baud_show, NULL);
233 static ssize_t dgnc_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf)
235 struct dgnc_board *bd;
239 DGNC_VERIFY_BOARD(p, bd);
241 for (i = 0; i < bd->nasync; i++) {
242 if (bd->channels[i]->ch_open_count) {
243 count += snprintf(buf + count, PAGE_SIZE - count,
244 "%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum,
245 (bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
246 (bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
247 (bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
248 (bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
249 (bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
250 (bd->channels[i]->ch_mistat & UART_MSR_RI) ? "RI" : "");
252 count += snprintf(buf + count, PAGE_SIZE - count,
253 "%d\n", bd->channels[i]->ch_portnum);
258 static DEVICE_ATTR(ports_msignals, S_IRUSR, dgnc_ports_msignals_show, NULL);
261 static ssize_t dgnc_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf)
263 struct dgnc_board *bd;
267 DGNC_VERIFY_BOARD(p, bd);
269 for (i = 0; i < bd->nasync; i++) {
270 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
271 bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag);
275 static DEVICE_ATTR(ports_iflag, S_IRUSR, dgnc_ports_iflag_show, NULL);
278 static ssize_t dgnc_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf)
280 struct dgnc_board *bd;
284 DGNC_VERIFY_BOARD(p, bd);
286 for (i = 0; i < bd->nasync; i++) {
287 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
288 bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag);
292 static DEVICE_ATTR(ports_cflag, S_IRUSR, dgnc_ports_cflag_show, NULL);
295 static ssize_t dgnc_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf)
297 struct dgnc_board *bd;
301 DGNC_VERIFY_BOARD(p, bd);
303 for (i = 0; i < bd->nasync; i++) {
304 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
305 bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag);
309 static DEVICE_ATTR(ports_oflag, S_IRUSR, dgnc_ports_oflag_show, NULL);
312 static ssize_t dgnc_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf)
314 struct dgnc_board *bd;
318 DGNC_VERIFY_BOARD(p, bd);
320 for (i = 0; i < bd->nasync; i++) {
321 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
322 bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag);
326 static DEVICE_ATTR(ports_lflag, S_IRUSR, dgnc_ports_lflag_show, NULL);
329 static ssize_t dgnc_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf)
331 struct dgnc_board *bd;
335 DGNC_VERIFY_BOARD(p, bd);
337 for (i = 0; i < bd->nasync; i++) {
338 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
339 bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags);
343 static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgnc_ports_digi_flag_show, NULL);
346 static ssize_t dgnc_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf)
348 struct dgnc_board *bd;
352 DGNC_VERIFY_BOARD(p, bd);
354 for (i = 0; i < bd->nasync; i++) {
355 count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
356 bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount);
360 static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgnc_ports_rxcount_show, NULL);
363 static ssize_t dgnc_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf)
365 struct dgnc_board *bd;
369 DGNC_VERIFY_BOARD(p, bd);
371 for (i = 0; i < bd->nasync; i++) {
372 count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
373 bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount);
377 static DEVICE_ATTR(ports_txcount, S_IRUSR, dgnc_ports_txcount_show, NULL);
380 /* this function creates the sys files that will export each signal status
381 * to sysfs each value will be put in a separate filename
383 void dgnc_create_ports_sysfiles(struct dgnc_board *bd)
387 dev_set_drvdata(&bd->pdev->dev, bd);
388 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state);
389 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud);
390 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
391 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
392 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
393 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
394 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
395 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
396 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
397 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
398 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_vpd);
399 rc |= device_create_file(&(bd->pdev->dev), &dev_attr_serial_number);
401 printk(KERN_ERR "DGNC: sysfs device_create_file failed!\n");
406 /* removes all the sys files created for that port */
407 void dgnc_remove_ports_sysfiles(struct dgnc_board *bd)
409 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state);
410 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud);
411 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
412 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
413 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
414 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
415 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
416 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
417 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
418 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
419 device_remove_file(&(bd->pdev->dev), &dev_attr_vpd);
420 device_remove_file(&(bd->pdev->dev), &dev_attr_serial_number);
424 static ssize_t dgnc_tty_state_show(struct device *d, struct device_attribute *attr, char *buf)
426 struct dgnc_board *bd;
427 struct channel_t *ch;
432 un = dev_get_drvdata(d);
433 if (!un || un->magic != DGNC_UNIT_MAGIC)
436 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
439 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
441 if (bd->state != BOARD_READY)
444 return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed");
446 static DEVICE_ATTR(state, S_IRUSR, dgnc_tty_state_show, NULL);
449 static ssize_t dgnc_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf)
451 struct dgnc_board *bd;
452 struct channel_t *ch;
457 un = dev_get_drvdata(d);
458 if (!un || un->magic != DGNC_UNIT_MAGIC)
461 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
464 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
466 if (bd->state != BOARD_READY)
469 return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_old_baud);
471 static DEVICE_ATTR(baud, S_IRUSR, dgnc_tty_baud_show, NULL);
474 static ssize_t dgnc_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf)
476 struct dgnc_board *bd;
477 struct channel_t *ch;
482 un = dev_get_drvdata(d);
483 if (!un || un->magic != DGNC_UNIT_MAGIC)
486 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
489 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
491 if (bd->state != BOARD_READY)
494 if (ch->ch_open_count) {
495 return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
496 (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
497 (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
498 (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
499 (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
500 (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
501 (ch->ch_mistat & UART_MSR_RI) ? "RI" : "");
505 static DEVICE_ATTR(msignals, S_IRUSR, dgnc_tty_msignals_show, NULL);
508 static ssize_t dgnc_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf)
510 struct dgnc_board *bd;
511 struct channel_t *ch;
516 un = dev_get_drvdata(d);
517 if (!un || un->magic != DGNC_UNIT_MAGIC)
520 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
523 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
525 if (bd->state != BOARD_READY)
528 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
530 static DEVICE_ATTR(iflag, S_IRUSR, dgnc_tty_iflag_show, NULL);
533 static ssize_t dgnc_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf)
535 struct dgnc_board *bd;
536 struct channel_t *ch;
541 un = dev_get_drvdata(d);
542 if (!un || un->magic != DGNC_UNIT_MAGIC)
545 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
548 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
550 if (bd->state != BOARD_READY)
553 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
555 static DEVICE_ATTR(cflag, S_IRUSR, dgnc_tty_cflag_show, NULL);
558 static ssize_t dgnc_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf)
560 struct dgnc_board *bd;
561 struct channel_t *ch;
566 un = dev_get_drvdata(d);
567 if (!un || un->magic != DGNC_UNIT_MAGIC)
570 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
573 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
575 if (bd->state != BOARD_READY)
578 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
580 static DEVICE_ATTR(oflag, S_IRUSR, dgnc_tty_oflag_show, NULL);
583 static ssize_t dgnc_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf)
585 struct dgnc_board *bd;
586 struct channel_t *ch;
591 un = dev_get_drvdata(d);
592 if (!un || un->magic != DGNC_UNIT_MAGIC)
595 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
598 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
600 if (bd->state != BOARD_READY)
603 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
605 static DEVICE_ATTR(lflag, S_IRUSR, dgnc_tty_lflag_show, NULL);
608 static ssize_t dgnc_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf)
610 struct dgnc_board *bd;
611 struct channel_t *ch;
616 un = dev_get_drvdata(d);
617 if (!un || un->magic != DGNC_UNIT_MAGIC)
620 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
623 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
625 if (bd->state != BOARD_READY)
628 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
630 static DEVICE_ATTR(digi_flag, S_IRUSR, dgnc_tty_digi_flag_show, NULL);
633 static ssize_t dgnc_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf)
635 struct dgnc_board *bd;
636 struct channel_t *ch;
641 un = dev_get_drvdata(d);
642 if (!un || un->magic != DGNC_UNIT_MAGIC)
645 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
648 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
650 if (bd->state != BOARD_READY)
653 return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
655 static DEVICE_ATTR(rxcount, S_IRUSR, dgnc_tty_rxcount_show, NULL);
658 static ssize_t dgnc_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf)
660 struct dgnc_board *bd;
661 struct channel_t *ch;
666 un = dev_get_drvdata(d);
667 if (!un || un->magic != DGNC_UNIT_MAGIC)
670 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
673 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
675 if (bd->state != BOARD_READY)
678 return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
680 static DEVICE_ATTR(txcount, S_IRUSR, dgnc_tty_txcount_show, NULL);
683 static ssize_t dgnc_tty_name_show(struct device *d, struct device_attribute *attr, char *buf)
685 struct dgnc_board *bd;
686 struct channel_t *ch;
691 un = dev_get_drvdata(d);
692 if (!un || un->magic != DGNC_UNIT_MAGIC)
695 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
698 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
700 if (bd->state != BOARD_READY)
703 return snprintf(buf, PAGE_SIZE, "%sn%d%c\n",
704 (un->un_type == DGNC_PRINT) ? "pr" : "tty",
705 bd->boardnum + 1, 'a' + ch->ch_portnum);
707 static DEVICE_ATTR(custom_name, S_IRUSR, dgnc_tty_name_show, NULL);
710 static struct attribute *dgnc_sysfs_tty_entries[] = {
711 &dev_attr_state.attr,
713 &dev_attr_msignals.attr,
714 &dev_attr_iflag.attr,
715 &dev_attr_cflag.attr,
716 &dev_attr_oflag.attr,
717 &dev_attr_lflag.attr,
718 &dev_attr_digi_flag.attr,
719 &dev_attr_rxcount.attr,
720 &dev_attr_txcount.attr,
721 &dev_attr_custom_name.attr,
726 static struct attribute_group dgnc_tty_attribute_group = {
728 .attrs = dgnc_sysfs_tty_entries,
732 void dgnc_create_tty_sysfs(struct un_t *un, struct device *c)
736 ret = sysfs_create_group(&c->kobj, &dgnc_tty_attribute_group);
738 dev_err(c, "dgnc: failed to create sysfs tty device attributes.\n");
739 sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);
743 dev_set_drvdata(c, un);
748 void dgnc_remove_tty_sysfs(struct device *c)
750 sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);