1 /*
2 * Copyright 2001-2017 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Michael Pfeiffer
7 * Adrien Destugues <pulkomandy@pulkomandy.tk>
8 */
9
10
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <termios.h>
14
15 #include <StorageKit.h>
16 #include <SupportKit.h>
17
18 #include "PrintTransportAddOn.h"
19
20
21 class SerialTransport : public BDataIO {
22 public:
23 SerialTransport(BDirectory* printer, BMessage* msg);
24 ~SerialTransport();
25
InitCheck()26 status_t InitCheck() { return fFile > -1 ? B_OK : B_ERROR; }
27
28 ssize_t Read(void* buffer, size_t size);
29 ssize_t Write(const void* buffer, size_t size);
30
31 private:
32 int fFile;
33 };
34
35
36 // Impelmentation of SerialTransport
SerialTransport(BDirectory * printer,BMessage * msg)37 SerialTransport::SerialTransport(BDirectory* printer, BMessage* msg)
38 : fFile(-1)
39 {
40 char address[80];
41 char device[B_PATH_NAME_LENGTH];
42 bool bidirectional = true;
43
44 unsigned int size = printer->ReadAttr("transport_address", B_STRING_TYPE, 0,
45 address, sizeof(address));
46 if (size <= 0 || size >= sizeof(address)) return;
47 address[size] = 0; // make sure string is 0-terminated
48
49 strcat(strcpy(device, "/dev/ports/"), address);
50 fFile = open(device, O_RDWR | O_EXCL, 0);
51 if (fFile < 0) {
52 // Try unidirectional access mode
53 bidirectional = false;
54 fFile = open(device, O_WRONLY | O_EXCL, 0);
55 }
56
57 if (fFile < 0)
58 return;
59
60 int32 baudrate;
61 size = printer->ReadAttr("transport_baudrate", B_INT32_TYPE, 0,
62 &baudrate, sizeof(baudrate));
63
64 struct termios options;
65 tcgetattr(fFile, &options);
66
67 cfmakeraw(&options);
68 options.c_cc[VTIME] = 10; // wait for data at most for 1 second
69 options.c_cc[VMIN] = 0; // allow to return 0 chars
70
71 if (size == sizeof(baudrate)) {
72 // Printer driver asked for a specific baudrate, configure it
73 cfsetispeed(&options, baudrate);
74 cfsetospeed(&options, baudrate);
75 }
76
77 tcsetattr(fFile, TCSANOW, &options);
78
79 if (msg == NULL) {
80 // Caller don't care about transport init message output content...
81 return;
82 }
83
84 msg->what = 'okok';
85 msg->AddBool("bidirectional", bidirectional);
86 msg->AddString("_serial/DeviceName", device);
87
88 }
89
90
~SerialTransport()91 SerialTransport::~SerialTransport()
92 {
93 if (InitCheck() == B_OK)
94 close(fFile);
95 }
96
97
98 ssize_t
Read(void * buffer,size_t size)99 SerialTransport::Read(void* buffer, size_t size)
100 {
101 return read(fFile, buffer, size);
102 }
103
104
105 ssize_t
Write(const void * buffer,size_t size)106 SerialTransport::Write(const void* buffer, size_t size)
107 {
108 return write(fFile, buffer, size);
109 }
110
111
112 BDataIO*
instantiate_transport(BDirectory * printer,BMessage * msg)113 instantiate_transport(BDirectory* printer, BMessage* msg)
114 {
115 SerialTransport* transport = new SerialTransport(printer, msg);
116 if (transport->InitCheck() == B_OK)
117 return transport;
118
119 delete transport;
120 return NULL;
121 }
122
123
124 status_t
list_transport_ports(BMessage * msg)125 list_transport_ports(BMessage* msg)
126 {
127 BDirectory dir("/dev/ports");
128 status_t rc;
129
130 if ((rc=dir.InitCheck()) != B_OK)
131 return rc;
132
133 if ((rc=dir.Rewind()) != B_OK)
134 return rc;
135
136 entry_ref ref;
137 while (dir.GetNextRef(&ref) == B_OK)
138 msg->AddString("port_id", ref.name);
139
140 return B_OK;
141 }
142