1/*
2 * Copyright 2004, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the Haiku License.
4 */
5
6#include <new>
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include <lock.h>
13
14#include "tty_private.h"
15
16
17//#define TTY_TRACE
18#ifdef TTY_TRACE
19#	define TRACE(x) dprintf x
20#else
21#	define TRACE(x)
22#endif
23
24#define DRIVER_NAME "tty"
25
26static const int kMaxCachedSemaphores = 8;
27
28int32 api_version = B_CUR_DRIVER_API_VERSION;
29
30char *gDeviceNames[kNumTTYs * 2 + 3];
31	// reserve space for "pt/" and "tt/" entries, "ptmx", "tty", and the
32	// terminating NULL
33
34static mutex sTTYLocks[kNumTTYs];
35
36struct mutex gGlobalTTYLock;
37struct mutex gTTYCookieLock;
38struct recursive_lock gTTYRequestLock;
39
40
41status_t
42init_hardware(void)
43{
44	TRACE((DRIVER_NAME ": init_hardware()\n"));
45	return B_OK;
46}
47
48
49status_t
50init_driver(void)
51{
52	TRACE((DRIVER_NAME ": init_driver()\n"));
53
54	memset(gDeviceNames, 0, sizeof(gDeviceNames));
55
56	// create the request mutex
57	recursive_lock_init(&gTTYRequestLock, "tty requests");
58
59	// create the global mutex
60	mutex_init(&gGlobalTTYLock, "tty global");
61
62	// create the cookie mutex
63	mutex_init(&gTTYCookieLock, "tty cookies");
64
65	// create driver name array and initialize basic TTY structures
66
67	char letter = 'p';
68	int8 digit = 0;
69
70	for (uint32 i = 0; i < kNumTTYs; i++) {
71		// For compatibility, we have to create the same mess in /dev/pt and
72		// /dev/tt as BeOS does: we publish devices p0, p1, ..., pf, r1, ...,
73		// sf. It would be nice if we could drop compatibility and create
74		// something better. In fact we already don't need the master devices
75		// anymore, since "/dev/ptmx" does the job. The slaves entries could
76		// be published on the fly when a master is opened (e.g via
77		// vfs_create_special_node()).
78		char buffer[64];
79
80		snprintf(buffer, sizeof(buffer), "pt/%c%x", letter, digit);
81		gDeviceNames[i] = strdup(buffer);
82
83		snprintf(buffer, sizeof(buffer), "tt/%c%x", letter, digit);
84		gDeviceNames[i + kNumTTYs] = strdup(buffer);
85
86		if (++digit > 15)
87			digit = 0, letter++;
88
89		mutex_init(&sTTYLocks[i], "tty lock");
90		reset_tty(&gMasterTTYs[i], i, &sTTYLocks[i], true);
91		reset_tty(&gSlaveTTYs[i], i, &sTTYLocks[i], false);
92		reset_tty_settings(&gTTYSettings[i], i);
93
94		if (!gDeviceNames[i] || !gDeviceNames[i + kNumTTYs]) {
95			uninit_driver();
96			return B_NO_MEMORY;
97		}
98	}
99
100	gDeviceNames[2 * kNumTTYs] = (char *)"ptmx";
101	gDeviceNames[2 * kNumTTYs + 1] = (char *)"tty";
102
103	tty_add_debugger_commands();
104
105	return B_OK;
106}
107
108
109void
110uninit_driver(void)
111{
112	TRACE((DRIVER_NAME ": uninit_driver()\n"));
113
114	tty_remove_debugger_commands();
115
116	for (int32 i = 0; i < (int32)kNumTTYs * 2; i++)
117		free(gDeviceNames[i]);
118
119	for (int32 i = 0; i < (int32)kNumTTYs; i++)
120		mutex_destroy(&sTTYLocks[i]);
121
122	recursive_lock_destroy(&gTTYRequestLock);
123	mutex_destroy(&gTTYCookieLock);
124	mutex_destroy(&gGlobalTTYLock);
125}
126
127
128const char **
129publish_devices(void)
130{
131	TRACE((DRIVER_NAME ": publish_devices()\n"));
132	return const_cast<const char **>(gDeviceNames);
133}
134
135
136device_hooks *
137find_device(const char *name)
138{
139	TRACE((DRIVER_NAME ": find_device(\"%s\")\n", name));
140
141	for (uint32 i = 0; gDeviceNames[i] != NULL; i++)
142		if (!strcmp(name, gDeviceNames[i])) {
143			return i < kNumTTYs || i == (2 * kNumTTYs)
144				? &gMasterTTYHooks : &gSlaveTTYHooks;
145		}
146
147	return NULL;
148}
149
150