diff options
-rw-r--r-- | net/irda/ircomm/ircomm_tty.c | 256 |
1 files changed, 138 insertions, 118 deletions
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 086d5ef098fd..811984d9324b 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/fs.h> | 35 | #include <linux/fs.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <linux/seq_file.h> | ||
37 | #include <linux/termios.h> | 38 | #include <linux/termios.h> |
38 | #include <linux/tty.h> | 39 | #include <linux/tty.h> |
39 | #include <linux/interrupt.h> | 40 | #include <linux/interrupt.h> |
@@ -72,8 +73,7 @@ static int ircomm_tty_control_indication(void *instance, void *sap, | |||
72 | static void ircomm_tty_flow_indication(void *instance, void *sap, | 73 | static void ircomm_tty_flow_indication(void *instance, void *sap, |
73 | LOCAL_FLOW cmd); | 74 | LOCAL_FLOW cmd); |
74 | #ifdef CONFIG_PROC_FS | 75 | #ifdef CONFIG_PROC_FS |
75 | static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len, | 76 | static const struct file_operations ircomm_tty_proc_fops; |
76 | int *eof, void *unused); | ||
77 | #endif /* CONFIG_PROC_FS */ | 77 | #endif /* CONFIG_PROC_FS */ |
78 | static struct tty_driver *driver; | 78 | static struct tty_driver *driver; |
79 | 79 | ||
@@ -98,7 +98,7 @@ static const struct tty_operations ops = { | |||
98 | .hangup = ircomm_tty_hangup, | 98 | .hangup = ircomm_tty_hangup, |
99 | .wait_until_sent = ircomm_tty_wait_until_sent, | 99 | .wait_until_sent = ircomm_tty_wait_until_sent, |
100 | #ifdef CONFIG_PROC_FS | 100 | #ifdef CONFIG_PROC_FS |
101 | .read_proc = ircomm_tty_read_proc, | 101 | .proc_fops = &ircomm_tty_proc_fops, |
102 | #endif /* CONFIG_PROC_FS */ | 102 | #endif /* CONFIG_PROC_FS */ |
103 | }; | 103 | }; |
104 | 104 | ||
@@ -1245,150 +1245,170 @@ static void ircomm_tty_flow_indication(void *instance, void *sap, | |||
1245 | } | 1245 | } |
1246 | 1246 | ||
1247 | #ifdef CONFIG_PROC_FS | 1247 | #ifdef CONFIG_PROC_FS |
1248 | static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf) | 1248 | static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) |
1249 | { | 1249 | { |
1250 | int ret=0; | 1250 | char sep; |
1251 | 1251 | ||
1252 | ret += sprintf(buf+ret, "State: %s\n", ircomm_tty_state[self->state]); | 1252 | seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]); |
1253 | 1253 | ||
1254 | ret += sprintf(buf+ret, "Service type: "); | 1254 | seq_puts(m, "Service type: "); |
1255 | if (self->service_type & IRCOMM_9_WIRE) | 1255 | if (self->service_type & IRCOMM_9_WIRE) |
1256 | ret += sprintf(buf+ret, "9_WIRE"); | 1256 | seq_puts(m, "9_WIRE"); |
1257 | else if (self->service_type & IRCOMM_3_WIRE) | 1257 | else if (self->service_type & IRCOMM_3_WIRE) |
1258 | ret += sprintf(buf+ret, "3_WIRE"); | 1258 | seq_puts(m, "3_WIRE"); |
1259 | else if (self->service_type & IRCOMM_3_WIRE_RAW) | 1259 | else if (self->service_type & IRCOMM_3_WIRE_RAW) |
1260 | ret += sprintf(buf+ret, "3_WIRE_RAW"); | 1260 | seq_puts(m, "3_WIRE_RAW"); |
1261 | else | 1261 | else |
1262 | ret += sprintf(buf+ret, "No common service type!\n"); | 1262 | seq_puts(m, "No common service type!\n"); |
1263 | ret += sprintf(buf+ret, "\n"); | 1263 | seq_putc(m, '\n'); |
1264 | 1264 | ||
1265 | ret += sprintf(buf+ret, "Port name: %s\n", self->settings.port_name); | 1265 | seq_printf(m, "Port name: %s\n", self->settings.port_name); |
1266 | 1266 | ||
1267 | ret += sprintf(buf+ret, "DTE status: "); | 1267 | seq_printf(m, "DTE status:"); |
1268 | if (self->settings.dte & IRCOMM_RTS) | 1268 | sep = ' '; |
1269 | ret += sprintf(buf+ret, "RTS|"); | 1269 | if (self->settings.dte & IRCOMM_RTS) { |
1270 | if (self->settings.dte & IRCOMM_DTR) | 1270 | seq_printf(m, "%cRTS", sep); |
1271 | ret += sprintf(buf+ret, "DTR|"); | 1271 | sep = '|'; |
1272 | if (self->settings.dte) | 1272 | } |
1273 | ret--; /* remove the last | */ | 1273 | if (self->settings.dte & IRCOMM_DTR) { |
1274 | ret += sprintf(buf+ret, "\n"); | 1274 | seq_printf(m, "%cDTR", sep); |
1275 | 1275 | sep = '|'; | |
1276 | ret += sprintf(buf+ret, "DCE status: "); | 1276 | } |
1277 | if (self->settings.dce & IRCOMM_CTS) | 1277 | seq_putc(m, '\n'); |
1278 | ret += sprintf(buf+ret, "CTS|"); | 1278 | |
1279 | if (self->settings.dce & IRCOMM_DSR) | 1279 | seq_puts(m, "DCE status:"); |
1280 | ret += sprintf(buf+ret, "DSR|"); | 1280 | sep = ' '; |
1281 | if (self->settings.dce & IRCOMM_CD) | 1281 | if (self->settings.dce & IRCOMM_CTS) { |
1282 | ret += sprintf(buf+ret, "CD|"); | 1282 | seq_printf(m, "%cCTS", sep); |
1283 | if (self->settings.dce & IRCOMM_RI) | 1283 | sep = '|'; |
1284 | ret += sprintf(buf+ret, "RI|"); | 1284 | } |
1285 | if (self->settings.dce) | 1285 | if (self->settings.dce & IRCOMM_DSR) { |
1286 | ret--; /* remove the last | */ | 1286 | seq_printf(m, "%cDSR", sep); |
1287 | ret += sprintf(buf+ret, "\n"); | 1287 | sep = '|'; |
1288 | 1288 | } | |
1289 | ret += sprintf(buf+ret, "Configuration: "); | 1289 | if (self->settings.dce & IRCOMM_CD) { |
1290 | seq_printf(m, "%cCD", sep); | ||
1291 | sep = '|'; | ||
1292 | } | ||
1293 | if (self->settings.dce & IRCOMM_RI) { | ||
1294 | seq_printf(m, "%cRI", sep); | ||
1295 | sep = '|'; | ||
1296 | } | ||
1297 | seq_putc(m, '\n'); | ||
1298 | |||
1299 | seq_puts(m, "Configuration: "); | ||
1290 | if (!self->settings.null_modem) | 1300 | if (!self->settings.null_modem) |
1291 | ret += sprintf(buf+ret, "DTE <-> DCE\n"); | 1301 | seq_puts(m, "DTE <-> DCE\n"); |
1292 | else | 1302 | else |
1293 | ret += sprintf(buf+ret, | 1303 | seq_puts(m, "DTE <-> DTE (null modem emulation)\n"); |
1294 | "DTE <-> DTE (null modem emulation)\n"); | 1304 | |
1295 | 1305 | seq_printf(m, "Data rate: %d\n", self->settings.data_rate); | |
1296 | ret += sprintf(buf+ret, "Data rate: %d\n", self->settings.data_rate); | 1306 | |
1297 | 1307 | seq_puts(m, "Flow control:"); | |
1298 | ret += sprintf(buf+ret, "Flow control: "); | 1308 | sep = ' '; |
1299 | if (self->settings.flow_control & IRCOMM_XON_XOFF_IN) | 1309 | if (self->settings.flow_control & IRCOMM_XON_XOFF_IN) { |
1300 | ret += sprintf(buf+ret, "XON_XOFF_IN|"); | 1310 | seq_printf(m, "%cXON_XOFF_IN", sep); |
1301 | if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT) | 1311 | sep = '|'; |
1302 | ret += sprintf(buf+ret, "XON_XOFF_OUT|"); | 1312 | } |
1303 | if (self->settings.flow_control & IRCOMM_RTS_CTS_IN) | 1313 | if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT) { |
1304 | ret += sprintf(buf+ret, "RTS_CTS_IN|"); | 1314 | seq_printf(m, "%cXON_XOFF_OUT", sep); |
1305 | if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT) | 1315 | sep = '|'; |
1306 | ret += sprintf(buf+ret, "RTS_CTS_OUT|"); | 1316 | } |
1307 | if (self->settings.flow_control & IRCOMM_DSR_DTR_IN) | 1317 | if (self->settings.flow_control & IRCOMM_RTS_CTS_IN) { |
1308 | ret += sprintf(buf+ret, "DSR_DTR_IN|"); | 1318 | seq_printf(m, "%cRTS_CTS_IN", sep); |
1309 | if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT) | 1319 | sep = '|'; |
1310 | ret += sprintf(buf+ret, "DSR_DTR_OUT|"); | 1320 | } |
1311 | if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN) | 1321 | if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT) { |
1312 | ret += sprintf(buf+ret, "ENQ_ACK_IN|"); | 1322 | seq_printf(m, "%cRTS_CTS_OUT", sep); |
1313 | if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT) | 1323 | sep = '|'; |
1314 | ret += sprintf(buf+ret, "ENQ_ACK_OUT|"); | 1324 | } |
1315 | if (self->settings.flow_control) | 1325 | if (self->settings.flow_control & IRCOMM_DSR_DTR_IN) { |
1316 | ret--; /* remove the last | */ | 1326 | seq_printf(m, "%cDSR_DTR_IN", sep); |
1317 | ret += sprintf(buf+ret, "\n"); | 1327 | sep = '|'; |
1318 | 1328 | } | |
1319 | ret += sprintf(buf+ret, "Flags: "); | 1329 | if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT) { |
1320 | if (self->flags & ASYNC_CTS_FLOW) | 1330 | seq_printf(m, "%cDSR_DTR_OUT", sep); |
1321 | ret += sprintf(buf+ret, "ASYNC_CTS_FLOW|"); | 1331 | sep = '|'; |
1322 | if (self->flags & ASYNC_CHECK_CD) | 1332 | } |
1323 | ret += sprintf(buf+ret, "ASYNC_CHECK_CD|"); | 1333 | if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN) { |
1324 | if (self->flags & ASYNC_INITIALIZED) | 1334 | seq_printf(m, "%cENQ_ACK_IN", sep); |
1325 | ret += sprintf(buf+ret, "ASYNC_INITIALIZED|"); | 1335 | sep = '|'; |
1326 | if (self->flags & ASYNC_LOW_LATENCY) | 1336 | } |
1327 | ret += sprintf(buf+ret, "ASYNC_LOW_LATENCY|"); | 1337 | if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT) { |
1328 | if (self->flags & ASYNC_CLOSING) | 1338 | seq_printf(m, "%cENQ_ACK_OUT", sep); |
1329 | ret += sprintf(buf+ret, "ASYNC_CLOSING|"); | 1339 | sep = '|'; |
1330 | if (self->flags & ASYNC_NORMAL_ACTIVE) | 1340 | } |
1331 | ret += sprintf(buf+ret, "ASYNC_NORMAL_ACTIVE|"); | 1341 | seq_putc(m, '\n'); |
1332 | if (self->flags) | 1342 | |
1333 | ret--; /* remove the last | */ | 1343 | seq_puts(m, "Flags:"); |
1334 | ret += sprintf(buf+ret, "\n"); | 1344 | sep = ' '; |
1335 | 1345 | if (self->flags & ASYNC_CTS_FLOW) { | |
1336 | ret += sprintf(buf+ret, "Role: %s\n", self->client ? | 1346 | seq_printf(m, "%cASYNC_CTS_FLOW", sep); |
1337 | "client" : "server"); | 1347 | sep = '|'; |
1338 | ret += sprintf(buf+ret, "Open count: %d\n", self->open_count); | 1348 | } |
1339 | ret += sprintf(buf+ret, "Max data size: %d\n", self->max_data_size); | 1349 | if (self->flags & ASYNC_CHECK_CD) { |
1340 | ret += sprintf(buf+ret, "Max header size: %d\n", self->max_header_size); | 1350 | seq_printf(m, "%cASYNC_CHECK_CD", sep); |
1351 | sep = '|'; | ||
1352 | } | ||
1353 | if (self->flags & ASYNC_INITIALIZED) { | ||
1354 | seq_printf(m, "%cASYNC_INITIALIZED", sep); | ||
1355 | sep = '|'; | ||
1356 | } | ||
1357 | if (self->flags & ASYNC_LOW_LATENCY) { | ||
1358 | seq_printf(m, "%cASYNC_LOW_LATENCY", sep); | ||
1359 | sep = '|'; | ||
1360 | } | ||
1361 | if (self->flags & ASYNC_CLOSING) { | ||
1362 | seq_printf(m, "%cASYNC_CLOSING", sep); | ||
1363 | sep = '|'; | ||
1364 | } | ||
1365 | if (self->flags & ASYNC_NORMAL_ACTIVE) { | ||
1366 | seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep); | ||
1367 | sep = '|'; | ||
1368 | } | ||
1369 | seq_putc(m, '\n'); | ||
1370 | |||
1371 | seq_printf(m, "Role: %s\n", self->client ? "client" : "server"); | ||
1372 | seq_printf(m, "Open count: %d\n", self->open_count); | ||
1373 | seq_printf(m, "Max data size: %d\n", self->max_data_size); | ||
1374 | seq_printf(m, "Max header size: %d\n", self->max_header_size); | ||
1341 | 1375 | ||
1342 | if (self->tty) | 1376 | if (self->tty) |
1343 | ret += sprintf(buf+ret, "Hardware: %s\n", | 1377 | seq_printf(m, "Hardware: %s\n", |
1344 | self->tty->hw_stopped ? "Stopped" : "Running"); | 1378 | self->tty->hw_stopped ? "Stopped" : "Running"); |
1345 | |||
1346 | ret += sprintf(buf+ret, "\n"); | ||
1347 | return ret; | ||
1348 | } | 1379 | } |
1349 | 1380 | ||
1350 | 1381 | static int ircomm_tty_proc_show(struct seq_file *m, void *v) | |
1351 | /* | ||
1352 | * Function ircomm_tty_read_proc (buf, start, offset, len, eof, unused) | ||
1353 | * | ||
1354 | * | ||
1355 | * | ||
1356 | */ | ||
1357 | static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len, | ||
1358 | int *eof, void *unused) | ||
1359 | { | 1382 | { |
1360 | struct ircomm_tty_cb *self; | 1383 | struct ircomm_tty_cb *self; |
1361 | int count = 0, l; | ||
1362 | off_t begin = 0; | ||
1363 | unsigned long flags; | 1384 | unsigned long flags; |
1364 | 1385 | ||
1365 | spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags); | 1386 | spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags); |
1366 | 1387 | ||
1367 | self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty); | 1388 | self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty); |
1368 | while ((self != NULL) && (count < 4000)) { | 1389 | while (self != NULL) { |
1369 | if (self->magic != IRCOMM_TTY_MAGIC) | 1390 | if (self->magic != IRCOMM_TTY_MAGIC) |
1370 | break; | 1391 | break; |
1371 | 1392 | ||
1372 | l = ircomm_tty_line_info(self, buf + count); | 1393 | ircomm_tty_line_info(self, m); |
1373 | count += l; | ||
1374 | if (count+begin > offset+len) | ||
1375 | goto done; | ||
1376 | if (count+begin < offset) { | ||
1377 | begin += count; | ||
1378 | count = 0; | ||
1379 | } | ||
1380 | |||
1381 | self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty); | 1394 | self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty); |
1382 | } | 1395 | } |
1383 | *eof = 1; | ||
1384 | done: | ||
1385 | spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags); | 1396 | spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags); |
1397 | return 0; | ||
1398 | } | ||
1386 | 1399 | ||
1387 | if (offset >= count+begin) | 1400 | static int ircomm_tty_proc_open(struct inode *inode, struct file *file) |
1388 | return 0; | 1401 | { |
1389 | *start = buf + (offset-begin); | 1402 | return single_open(file, ircomm_tty_proc_show, NULL); |
1390 | return ((len < begin+count-offset) ? len : begin+count-offset); | ||
1391 | } | 1403 | } |
1404 | |||
1405 | static const struct file_operations ircomm_tty_proc_fops = { | ||
1406 | .owner = THIS_MODULE, | ||
1407 | .open = ircomm_tty_proc_open, | ||
1408 | .read = seq_read, | ||
1409 | .llseek = seq_lseek, | ||
1410 | .release = single_release, | ||
1411 | }; | ||
1392 | #endif /* CONFIG_PROC_FS */ | 1412 | #endif /* CONFIG_PROC_FS */ |
1393 | 1413 | ||
1394 | MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); | 1414 | MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); |