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