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 7#include "tty_private.h" 8 9#include <stdlib.h> 10#include <string.h> 11#include <util/AutoLock.h> 12 13 14//#define MASTER_TRACE 15#ifdef MASTER_TRACE 16# define TRACE(x) dprintf x 17#else 18# define TRACE(x) ; 19#endif 20 21 22struct master_cookie : tty_cookie { 23}; 24 25 26struct tty gMasterTTYs[kNumTTYs]; 27 28 29static status_t 30master_service(struct tty *tty, uint32 op) 31{ 32 // nothing here yet 33 return B_OK; 34} 35 36 37static status_t 38create_master_cookie(master_cookie *&cookie, struct tty *master, 39 struct tty *slave, uint32 openMode) 40{ 41 cookie = (master_cookie*)malloc(sizeof(struct master_cookie)); 42 if (cookie == NULL) 43 return B_NO_MEMORY; 44 45 status_t error = init_tty_cookie(cookie, master, slave, openMode); 46 if (error != B_OK) { 47 free(cookie); 48 return error; 49 } 50 51 return B_OK; 52} 53 54 55// #pragma mark - 56 57 58static status_t 59master_open(const char *name, uint32 flags, void **_cookie) 60{ 61 bool findUnusedTTY = strcmp(name, "ptmx") == 0; 62 63 int32 index = -1; 64 if (!findUnusedTTY) { 65 index = get_tty_index(name); 66 if (index >= (int32)kNumTTYs) 67 return B_ERROR; 68 } 69 70 TRACE(("master_open: TTY index = %ld (name = %s)\n", index, name)); 71 72 MutexLocker globalLocker(gGlobalTTYLock); 73 74 if (findUnusedTTY) { 75 for (index = 0; index < (int32)kNumTTYs; index++) { 76 if (gMasterTTYs[index].ref_count == 0) 77 break; 78 } 79 if (index >= (int32)kNumTTYs) 80 return ENOENT; 81 } else if (gMasterTTYs[index].ref_count > 0) { 82 // we're already open! 83 return B_BUSY; 84 } 85 86 status_t status = tty_open(&gMasterTTYs[index], &master_service); 87 if (status < B_OK) { 88 // initializing TTY failed 89 return status; 90 } 91 92 master_cookie *cookie; 93 status = create_master_cookie(cookie, &gMasterTTYs[index], 94 &gSlaveTTYs[index], flags); 95 if (status != B_OK) { 96 tty_close(&gMasterTTYs[index]); 97 return status; 98 } 99 100 add_tty_cookie(cookie); 101 102 *_cookie = cookie; 103 104 return B_OK; 105} 106 107 108static status_t 109master_close(void *_cookie) 110{ 111 master_cookie *cookie = (master_cookie *)_cookie; 112 113 TRACE(("master_close: cookie %p\n", _cookie)); 114 115 MutexLocker globalLocker(gGlobalTTYLock); 116 117 // close all connected slave cookies first 118 while (tty_cookie *slave = cookie->other_tty->cookies.Head()) 119 tty_close_cookie(slave); 120 121 // close the client cookie 122 tty_close_cookie(cookie); 123 124 return B_OK; 125} 126 127 128static status_t 129master_free_cookie(void *_cookie) 130{ 131 // The TTY is already closed. We only have to free the cookie. 132 master_cookie *cookie = (master_cookie *)_cookie; 133 134 MutexLocker globalLocker(gGlobalTTYLock); 135 uninit_tty_cookie(cookie); 136 globalLocker.Unlock(); 137 138 free(cookie); 139 140 return B_OK; 141} 142 143 144static status_t 145master_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) 146{ 147 master_cookie *cookie = (master_cookie *)_cookie; 148 149 TRACE(("master_ioctl: cookie %p, op %lu, buffer %p, length %lu\n", _cookie, op, buffer, length)); 150 151 return tty_ioctl(cookie, op, buffer, length); 152} 153 154 155static status_t 156master_read(void *_cookie, off_t offset, void *buffer, size_t *_length) 157{ 158 master_cookie *cookie = (master_cookie *)_cookie; 159 160 TRACE(("master_read: cookie %p, offset %Ld, buffer %p, length %lu\n", 161 _cookie, offset, buffer, *_length)); 162 163 status_t result = tty_input_read(cookie, buffer, _length); 164 165 TRACE(("master_read done: cookie %p, result: %lx, length %lu\n", _cookie, 166 result, *_length)); 167 168 return result; 169} 170 171 172static status_t 173master_write(void *_cookie, off_t offset, const void *buffer, size_t *_length) 174{ 175 master_cookie *cookie = (master_cookie *)_cookie; 176 177 TRACE(("master_write: cookie %p, offset %Ld, buffer %p, length %lu\n", 178 _cookie, offset, buffer, *_length)); 179 180 status_t result = tty_write_to_tty_master(cookie, buffer, _length); 181 182 TRACE(("master_write done: cookie %p, result: %lx, length %lu\n", _cookie, 183 result, *_length)); 184 185 return result; 186} 187 188 189static status_t 190master_select(void *_cookie, uint8 event, uint32 ref, selectsync *sync) 191{ 192 master_cookie *cookie = (master_cookie *)_cookie; 193 194 return tty_select(cookie, event, ref, sync); 195} 196 197 198static status_t 199master_deselect(void *_cookie, uint8 event, selectsync *sync) 200{ 201 master_cookie *cookie = (master_cookie *)_cookie; 202 203 return tty_deselect(cookie, event, sync); 204} 205 206 207device_hooks gMasterTTYHooks = { 208 &master_open, 209 &master_close, 210 &master_free_cookie, 211 &master_ioctl, 212 &master_read, 213 &master_write, 214 &master_select, 215 &master_deselect, 216 NULL, // read_pages() 217 NULL // write_pages() 218}; 219