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 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 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 91 SerialTransport::~SerialTransport() 92 { 93 if (InitCheck() == B_OK) 94 close(fFile); 95 } 96 97 98 ssize_t 99 SerialTransport::Read(void* buffer, size_t size) 100 { 101 return read(fFile, buffer, size); 102 } 103 104 105 ssize_t 106 SerialTransport::Write(const void* buffer, size_t size) 107 { 108 return write(fFile, buffer, size); 109 } 110 111 112 BDataIO* 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 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