Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / braille_display_private / brlapi_connection.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/api/braille_display_private/brlapi_connection.h"
6
7 #include <errno.h>
8
9 #include "base/message_loop/message_loop.h"
10 #include "base/sys_info.h"
11
12 namespace extensions {
13 using base::MessageLoopForIO;
14 namespace api {
15 namespace braille_display_private {
16
17 namespace {
18 // Default virtual terminal.  This can be overriden by setting the
19 // WINDOWPATH environment variable.  This is only used when not running
20 // under Crhome OS (that is in aura for a Linux desktop).
21 // TODO(plundblad): Find a way to detect the controlling terminal of the
22 // X server.
23 static const int kDefaultTtyLinux = 7;
24 #if defined(OS_CHROMEOS)
25 // The GUI is always running on vt1 in Chrome OS.
26 static const int kDefaultTtyChromeOS = 1;
27 #endif
28 }  // namespace
29
30 class BrlapiConnectionImpl : public BrlapiConnection,
31                              MessageLoopForIO::Watcher {
32  public:
33   explicit BrlapiConnectionImpl(LibBrlapiLoader* loader) :
34       libbrlapi_loader_(loader) {}
35
36   virtual ~BrlapiConnectionImpl() {
37     Disconnect();
38   }
39
40   virtual ConnectResult Connect(const OnDataReadyCallback& on_data_ready)
41       override;
42   virtual void Disconnect() override;
43   virtual bool Connected() override { return handle_; }
44   virtual brlapi_error_t* BrlapiError() override;
45   virtual std::string BrlapiStrError() override;
46   virtual bool GetDisplaySize(size_t* size) override;
47   virtual bool WriteDots(const unsigned char* cells) override;
48   virtual int ReadKey(brlapi_keyCode_t* keyCode) override;
49
50   // MessageLoopForIO::Watcher
51   virtual void OnFileCanReadWithoutBlocking(int fd) override {
52     on_data_ready_.Run();
53   }
54
55   virtual void OnFileCanWriteWithoutBlocking(int fd) override {}
56
57  private:
58   bool CheckConnected();
59   ConnectResult ConnectResultForError();
60
61   LibBrlapiLoader* libbrlapi_loader_;
62   scoped_ptr<brlapi_handle_t, base::FreeDeleter> handle_;
63   MessageLoopForIO::FileDescriptorWatcher fd_controller_;
64   OnDataReadyCallback on_data_ready_;
65
66   DISALLOW_COPY_AND_ASSIGN(BrlapiConnectionImpl);
67 };
68
69 BrlapiConnection::BrlapiConnection() {
70 }
71
72 BrlapiConnection::~BrlapiConnection() {
73 }
74
75 scoped_ptr<BrlapiConnection> BrlapiConnection::Create(
76     LibBrlapiLoader* loader) {
77   DCHECK(loader->loaded());
78   return scoped_ptr<BrlapiConnection>(new BrlapiConnectionImpl(loader));
79 }
80
81 BrlapiConnection::ConnectResult BrlapiConnectionImpl::Connect(
82     const OnDataReadyCallback& on_data_ready) {
83   DCHECK(!handle_);
84   handle_.reset((brlapi_handle_t*) malloc(
85       libbrlapi_loader_->brlapi_getHandleSize()));
86   int fd = libbrlapi_loader_->brlapi__openConnection(handle_.get(), NULL, NULL);
87   if (fd < 0) {
88     handle_.reset();
89     VLOG(1) << "Error connecting to brlapi: " << BrlapiStrError();
90     return ConnectResultForError();
91   }
92   int path[2] = {0, 0};
93   int pathElements = 0;
94 #if defined(OS_CHROMEOS)
95   if (base::SysInfo::IsRunningOnChromeOS())
96     path[pathElements++] = kDefaultTtyChromeOS;
97 #endif
98   if (pathElements == 0 && getenv("WINDOWPATH") == NULL)
99     path[pathElements++] = kDefaultTtyLinux;
100   if (libbrlapi_loader_->brlapi__enterTtyModeWithPath(
101           handle_.get(), path, pathElements, NULL) < 0) {
102     LOG(ERROR) << "brlapi: couldn't enter tty mode: " << BrlapiStrError();
103     Disconnect();
104     return CONNECT_ERROR_RETRY;
105   }
106
107   size_t size;
108   if (!GetDisplaySize(&size)) {
109     // Error already logged.
110     Disconnect();
111     return CONNECT_ERROR_RETRY;
112   }
113
114   // A display size of 0 means no display connected.  We can't reliably
115   // detect when a display gets connected, so fail and let the caller
116   // retry connecting.
117   if (size == 0) {
118     VLOG(1) << "No braille display connected";
119     Disconnect();
120     return CONNECT_ERROR_RETRY;
121   }
122
123   const brlapi_keyCode_t extraKeys[] = {
124       BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_OFFLINE,
125       // brltty 5.1 converts dot input to Unicode characters unless we
126       // explicitly accept this command.
127       BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_PASSDOTS,
128   };
129   if (libbrlapi_loader_->brlapi__acceptKeys(
130           handle_.get(), brlapi_rangeType_command, extraKeys,
131           arraysize(extraKeys)) < 0) {
132     LOG(ERROR) << "Couldn't acceptKeys: " << BrlapiStrError();
133     Disconnect();
134     return CONNECT_ERROR_RETRY;
135   }
136
137   if (!MessageLoopForIO::current()->WatchFileDescriptor(
138           fd, true, MessageLoopForIO::WATCH_READ, &fd_controller_, this)) {
139     LOG(ERROR) << "Couldn't watch file descriptor " << fd;
140     Disconnect();
141     return CONNECT_ERROR_RETRY;
142   }
143
144   on_data_ready_ = on_data_ready;
145
146   return CONNECT_SUCCESS;
147 }
148
149 void BrlapiConnectionImpl::Disconnect() {
150   if (!handle_) {
151     return;
152   }
153   fd_controller_.StopWatchingFileDescriptor();
154   libbrlapi_loader_->brlapi__closeConnection(
155       handle_.get());
156   handle_.reset();
157 }
158
159 brlapi_error_t* BrlapiConnectionImpl::BrlapiError() {
160   return libbrlapi_loader_->brlapi_error_location();
161 }
162
163 std::string BrlapiConnectionImpl::BrlapiStrError() {
164   return libbrlapi_loader_->brlapi_strerror(BrlapiError());
165 }
166
167 bool BrlapiConnectionImpl::GetDisplaySize(size_t* size) {
168   if (!CheckConnected()) {
169     return false;
170   }
171   unsigned int columns, rows;
172   if (libbrlapi_loader_->brlapi__getDisplaySize(
173           handle_.get(), &columns, &rows) < 0) {
174     LOG(ERROR) << "Couldn't get braille display size " << BrlapiStrError();
175     return false;
176   }
177   *size = columns * rows;
178   return true;
179 }
180
181 bool BrlapiConnectionImpl::WriteDots(const unsigned char* cells) {
182   if (!CheckConnected())
183     return false;
184   if (libbrlapi_loader_->brlapi__writeDots(handle_.get(), cells) < 0) {
185     VLOG(1) << "Couldn't write to brlapi: " << BrlapiStrError();
186     return false;
187   }
188   return true;
189 }
190
191 int BrlapiConnectionImpl::ReadKey(brlapi_keyCode_t* key_code) {
192   if (!CheckConnected())
193     return -1;
194   return libbrlapi_loader_->brlapi__readKey(
195       handle_.get(), 0 /*wait*/, key_code);
196 }
197
198 bool BrlapiConnectionImpl::CheckConnected() {
199   if (!handle_) {
200     BrlapiError()->brlerrno = BRLAPI_ERROR_ILLEGAL_INSTRUCTION;
201     return false;
202   }
203   return true;
204 }
205
206 BrlapiConnection::ConnectResult BrlapiConnectionImpl::ConnectResultForError() {
207   const brlapi_error_t* error = BrlapiError();
208   // For the majority of users, the socket file will never exist because
209   // the daemon is never run.  Avoid retrying in this case, relying on
210   // the socket directory to change and trigger further tries if the
211   // daemon comes up later on.
212   if (error->brlerrno == BRLAPI_ERROR_LIBCERR
213       && error->libcerrno == ENOENT) {
214     return CONNECT_ERROR_NO_RETRY;
215   }
216   return CONNECT_ERROR_RETRY;
217 }
218
219 }  // namespace braille_display_private
220 }  // namespace api
221 }  // namespace extensions