• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <windows.h>
6 
7 #include "chrome/browser/extensions/api/serial/serial_io_handler_win.h"
8 
9 #include "base/win/windows_version.h"
10 
11 namespace {
12 const base::PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
13 }  // namespace
14 
15 namespace extensions {
16 
17 // static
Create()18 scoped_refptr<SerialIoHandler> SerialIoHandler::Create() {
19   return new SerialIoHandlerWin();
20 }
21 
InitializeImpl()22 void SerialIoHandlerWin::InitializeImpl() {
23   DCHECK(!comm_context_);
24   DCHECK(!read_context_);
25   DCHECK(!write_context_);
26 
27   base::MessageLoopForIO::current()->RegisterIOHandler(file(), this);
28 
29   comm_context_.reset(new base::MessageLoopForIO::IOContext());
30   comm_context_->handler = this;
31   memset(&comm_context_->overlapped, 0, sizeof(comm_context_->overlapped));
32 
33   read_context_.reset(new base::MessageLoopForIO::IOContext());
34   read_context_->handler = this;
35   memset(&read_context_->overlapped, 0, sizeof(read_context_->overlapped));
36 
37   write_context_.reset(new base::MessageLoopForIO::IOContext());
38   write_context_->handler = this;
39   memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped));
40 }
41 
ReadImpl()42 void SerialIoHandlerWin::ReadImpl() {
43   DCHECK(CalledOnValidThread());
44   DCHECK(pending_read_buffer());
45   DCHECK_NE(file(), kInvalidPlatformFileValue);
46 
47   DWORD errors;
48   COMSTAT status;
49   if (!ClearCommError(file(), &errors, &status) || errors != 0) {
50     QueueReadCompleted(0, api::serial::RECEIVE_ERROR_SYSTEM_ERROR);
51     return;
52   }
53 
54   SetCommMask(file(), EV_RXCHAR);
55 
56   event_mask_ = 0;
57   BOOL ok = ::WaitCommEvent(file(), &event_mask_, &comm_context_->overlapped);
58   if (!ok && GetLastError() != ERROR_IO_PENDING) {
59     QueueReadCompleted(0, api::serial::RECEIVE_ERROR_SYSTEM_ERROR);
60   }
61   is_comm_pending_ = true;
62 }
63 
WriteImpl()64 void SerialIoHandlerWin::WriteImpl() {
65   DCHECK(CalledOnValidThread());
66   DCHECK(pending_write_buffer());
67   DCHECK_NE(file(), kInvalidPlatformFileValue);
68 
69   BOOL ok = ::WriteFile(file(),
70                         pending_write_buffer()->data(),
71                         pending_write_buffer_len(), NULL,
72                         &write_context_->overlapped);
73   if (!ok && GetLastError() != ERROR_IO_PENDING) {
74     QueueWriteCompleted(0, api::serial::SEND_ERROR_SYSTEM_ERROR);
75   }
76 }
77 
CancelReadImpl()78 void SerialIoHandlerWin::CancelReadImpl() {
79   DCHECK(CalledOnValidThread());
80   DCHECK_NE(file(), kInvalidPlatformFileValue);
81   ::CancelIo(file());
82 }
83 
CancelWriteImpl()84 void SerialIoHandlerWin::CancelWriteImpl() {
85   DCHECK(CalledOnValidThread());
86   DCHECK_NE(file(), kInvalidPlatformFileValue);
87   ::CancelIo(file());
88 }
89 
SerialIoHandlerWin()90 SerialIoHandlerWin::SerialIoHandlerWin()
91     : event_mask_(0),
92       is_comm_pending_(false) {
93 }
94 
~SerialIoHandlerWin()95 SerialIoHandlerWin::~SerialIoHandlerWin() {
96 }
97 
OnIOCompleted(base::MessageLoopForIO::IOContext * context,DWORD bytes_transferred,DWORD error)98 void SerialIoHandlerWin::OnIOCompleted(
99     base::MessageLoopForIO::IOContext* context,
100     DWORD bytes_transferred,
101     DWORD error) {
102   DCHECK(CalledOnValidThread());
103   if (context == comm_context_) {
104     if (read_canceled()) {
105       ReadCompleted(bytes_transferred, read_cancel_reason());
106     } else if (error != ERROR_SUCCESS && error != ERROR_OPERATION_ABORTED) {
107       ReadCompleted(0, api::serial::RECEIVE_ERROR_SYSTEM_ERROR);
108     } else if (pending_read_buffer()) {
109       BOOL ok = ::ReadFile(file(),
110                            pending_read_buffer()->data(),
111                            pending_read_buffer_len(),
112                            NULL,
113                            &read_context_->overlapped);
114       if (!ok && GetLastError() != ERROR_IO_PENDING) {
115         ReadCompleted(0, api::serial::RECEIVE_ERROR_SYSTEM_ERROR);
116       }
117     }
118   } else if (context == read_context_) {
119     if (read_canceled()) {
120       ReadCompleted(bytes_transferred, read_cancel_reason());
121     } else if (error != ERROR_SUCCESS && error != ERROR_OPERATION_ABORTED) {
122       ReadCompleted(0, api::serial::RECEIVE_ERROR_SYSTEM_ERROR);
123     } else {
124       ReadCompleted(
125           bytes_transferred,
126           error == ERROR_SUCCESS ? api::serial::RECEIVE_ERROR_NONE
127                                  : api::serial::RECEIVE_ERROR_SYSTEM_ERROR);
128     }
129   } else if (context == write_context_) {
130     DCHECK(pending_write_buffer());
131     if (write_canceled()) {
132       WriteCompleted(0, write_cancel_reason());
133     } else if (error != ERROR_SUCCESS && error != ERROR_OPERATION_ABORTED) {
134       WriteCompleted(0, api::serial::SEND_ERROR_SYSTEM_ERROR);
135     } else {
136       WriteCompleted(
137           bytes_transferred,
138           error == ERROR_SUCCESS ? api::serial::SEND_ERROR_NONE
139                                  : api::serial::SEND_ERROR_SYSTEM_ERROR);
140     }
141   } else {
142       NOTREACHED() << "Invalid IOContext";
143   }
144 }
145 
146 }  // namespace extensions
147