vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / print / transports / usb_port / USBTransport.cpp
blobe2e39750d3864bf6d4af773c9a6d49daf57dc487
1 /*
2 * Copyright 2001-2010 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Originally written based on Parallel port addon by Michael Pfeiffer,
6 * changes by Andreas Benzler, Philippe Houdoin
7 * Rewritten to use the USBKit by Ithamar R. Adema.
8 * (Using code from usb_printer.cpp by Michael Lotz)
10 * Authors:
11 * Ithamar R. Adema, <ithamar.adema@team-embedded.nl>
12 * Michael Pfeiffer,
13 * Andreas Benzler,
14 * Philippe Houdoin,
17 #include "PrintTransportAddOn.h"
19 #include <USBKit.h>
20 #include <String.h>
22 #include <HashString.h>
23 #include <HashMap.h>
25 #define PRINTER_INTERFACE_CLASS 0x07
26 #define PRINTER_INTERFACE_SUBCLASS 0x01
28 // printer interface types
29 #define PIT_UNIDIRECTIONAL 0x01
30 #define PIT_BIDIRECTIONAL 0x02
31 #define PIT_1284_4_COMPATIBLE 0x03
32 #define PIT_VENDOR_SPECIFIC 0xff
35 // TODO handle disconnection of printer during printing
36 // currently the USBPrinter will be deleted and USBTransport will still
37 // access the memory
38 class USBPrinter {
39 public:
40 USBPrinter(const BString& id, const BString& name,
41 const BUSBInterface *interface, const BUSBEndpoint *in, const BUSBEndpoint *out);
43 ssize_t Write(const void *buf, size_t size);
44 ssize_t Read(void *buf, size_t size);
46 const BUSBInterface *fInterface;
47 const BUSBEndpoint *fOut;
48 const BUSBEndpoint *fIn;
49 BString fName;
50 BString fID;
54 class USBPrinterRoster : public BUSBRoster {
55 public:
56 USBPrinterRoster();
58 status_t DeviceAdded(BUSBDevice *dev);
59 void DeviceRemoved(BUSBDevice *dev);
61 USBPrinter *Printer(const BString& key);
63 status_t ListPrinters(BMessage *msg);
64 private:
65 typedef HashMap<HashString,USBPrinter*> PrinterMap;
66 PrinterMap fPrinters;
70 class USBTransport : public BDataIO {
71 public:
72 USBTransport(BDirectory *printer, BMessage *msg);
73 ~USBTransport();
75 status_t InitCheck() { return fPrinter ? B_OK : B_ERROR; };
77 ssize_t Read(void *buffer, size_t size);
78 ssize_t Write(const void *buffer, size_t size);
80 private:
81 USBPrinter *fPrinter;
82 USBPrinterRoster *fRoster;
86 // Set transport_features so we stay loaded
87 uint32 transport_features = B_TRANSPORT_IS_HOTPLUG;
90 USBPrinterRoster::USBPrinterRoster()
92 Start();
96 USBPrinter *
97 USBPrinterRoster::Printer(const BString& key)
99 if (fPrinters.ContainsKey(key.String()))
100 return fPrinters.Get(key.String());
102 return NULL;
106 status_t
107 USBPrinterRoster::DeviceAdded(BUSBDevice *dev)
109 const BUSBConfiguration *config = dev->ActiveConfiguration();
110 const BUSBEndpoint *in = NULL, *out = NULL;
111 const BUSBInterface *printer = NULL;
113 // Try to find a working printer interface in this device
114 if (config) {
115 for (uint32 idx = 0; printer == NULL
116 && idx < config->CountInterfaces(); idx++) {
117 const BUSBInterface *interface = config->InterfaceAt(idx);
118 for (uint32 alt = 0; alt < interface->CountAlternates(); alt++) {
119 const BUSBInterface *alternate = interface->AlternateAt(alt);
120 if (alternate->Class() == PRINTER_INTERFACE_CLASS
121 && alternate->Subclass() == PRINTER_INTERFACE_SUBCLASS
122 && (alternate->Protocol() == PIT_UNIDIRECTIONAL
123 || alternate->Protocol() == PIT_BIDIRECTIONAL
124 || alternate->Protocol() == PIT_1284_4_COMPATIBLE)) {
125 // Found a usable Printer interface!
126 for (uint32 endpointIdx = 0;
127 endpointIdx < alternate->CountEndpoints();
128 endpointIdx++) {
129 const BUSBEndpoint *endpoint =
130 alternate->EndpointAt(endpointIdx);
131 if (!endpoint->IsBulk())
132 continue;
134 if (endpoint->IsInput())
135 in = endpoint;
136 else if (endpoint->IsOutput())
137 out = endpoint;
139 if (!in || !out)
140 continue;
142 printer = alternate;
143 ((BUSBInterface*)interface)->SetAlternate(alt);
144 break;
151 if (printer != NULL) {
152 // We found a working printer interface, lets determine a unique ID
153 // for it now, and a user identification for display in the Printers
154 // preference.
155 BString portId = dev->SerialNumberString();
156 if (!portId.Length()) {
157 // No persistent unique ID available, use the vendor/product
158 // ID for now. This will be unique as long as no two similar
159 // devices are attached.
160 portId << dev->VendorID() << "/" << dev->ProductID();
163 BString portName = dev->ManufacturerString();
164 if (portName.Length())
165 portName << " ";
166 portName << dev->ProductString();
168 //TODO: Do we want to use usb.ids to find proper name if strings
169 // are not supplied by USB?
171 fPrinters.Put(portId.String(), new USBPrinter(portId, portName,
172 printer, in, out));
175 return B_OK;
179 void
180 USBPrinterRoster::DeviceRemoved(BUSBDevice *dev)
182 PrinterMap::Iterator iterator = fPrinters.GetIterator();
183 while (iterator.HasNext()) {
184 const PrinterMap::Entry& entry = iterator.Next();
185 // If the device is in the list, remove it
186 if (entry.value->fInterface->Device() == dev) {
187 fPrinters.Remove(entry.key);
188 delete entry.value;
189 break;
195 status_t
196 USBPrinterRoster::ListPrinters(BMessage *msg)
198 PrinterMap::Iterator iterator = fPrinters.GetIterator();
199 while (iterator.HasNext()) {
200 const PrinterMap::Entry& entry = iterator.Next();
201 msg->AddString("port_id", entry.value->fID);
202 msg->AddString("port_name", entry.value->fName);
205 return B_OK;
209 USBPrinter::USBPrinter(const BString& id, const BString& name,
210 const BUSBInterface *intf, const BUSBEndpoint *in, const BUSBEndpoint *out)
211 : fInterface(intf), fOut(out), fIn(in), fName(name), fID(id)
216 //TODO: see usb_printer.cpp for error handling during read/write!
217 ssize_t
218 USBPrinter::Write(const void *buf, size_t size)
220 if (!buf || size <= 0)
221 return B_BAD_VALUE;
223 // NOTE: we can safely cast below as we're sending data _out_
224 return fOut->BulkTransfer((void*)buf, size);
228 ssize_t
229 USBPrinter::Read(void *buf, size_t size)
231 if (!buf || size <= 0)
232 return B_BAD_VALUE;
234 return fIn->BulkTransfer(buf, size);
238 // Implementation of transport add-on interface
240 BDataIO *
241 instantiate_transport(BDirectory *printer, BMessage *msg)
243 USBTransport *transport = new(std::nothrow) USBTransport(printer, msg);
244 if (transport != NULL && transport->InitCheck() == B_OK)
245 return transport;
247 delete transport;
248 return NULL;
252 // List detected printers
253 status_t
254 list_transport_ports(BMessage *msg)
256 USBPrinterRoster roster;
257 status_t status = roster.ListPrinters(msg);
258 roster.Stop();
259 return status;
263 // Implementation of USBTransport
264 USBTransport::USBTransport(BDirectory *printer, BMessage *msg)
265 : fPrinter(NULL)
267 BString key;
269 if (printer->ReadAttrString("transport_address", &key) != B_OK)
270 return;
272 fRoster = new(std::nothrow) USBPrinterRoster;
273 if (fRoster == NULL)
274 return;
276 fPrinter = fRoster->Printer(key.String());
277 if (fPrinter == NULL)
278 return;
280 // If caller doesn't care...
281 if (msg == NULL)
282 return;
284 // Fill up the message
285 msg->what = 'okok';
289 USBTransport::~USBTransport()
291 if (fRoster != NULL) {
292 fRoster->Stop();
293 delete fRoster;
298 ssize_t
299 USBTransport::Read(void *buffer, size_t size)
301 return fPrinter ? fPrinter->Read(buffer, size) : B_ERROR;
305 ssize_t
306 USBTransport::Write(const void *buffer, size_t size)
308 return fPrinter ? fPrinter->Write(buffer, size) : B_ERROR;