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)
11 * Ithamar R. Adema, <ithamar.adema@team-embedded.nl>
17 #include "PrintTransportAddOn.h"
22 #include <HashString.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
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
;
54 class USBPrinterRoster
: public BUSBRoster
{
58 status_t
DeviceAdded(BUSBDevice
*dev
);
59 void DeviceRemoved(BUSBDevice
*dev
);
61 USBPrinter
*Printer(const BString
& key
);
63 status_t
ListPrinters(BMessage
*msg
);
65 typedef HashMap
<HashString
,USBPrinter
*> PrinterMap
;
70 class USBTransport
: public BDataIO
{
72 USBTransport(BDirectory
*printer
, BMessage
*msg
);
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
);
82 USBPrinterRoster
*fRoster
;
86 // Set transport_features so we stay loaded
87 uint32 transport_features
= B_TRANSPORT_IS_HOTPLUG
;
90 USBPrinterRoster::USBPrinterRoster()
97 USBPrinterRoster::Printer(const BString
& key
)
99 if (fPrinters
.ContainsKey(key
.String()))
100 return fPrinters
.Get(key
.String());
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
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();
129 const BUSBEndpoint
*endpoint
=
130 alternate
->EndpointAt(endpointIdx
);
131 if (!endpoint
->IsBulk())
134 if (endpoint
->IsInput())
136 else if (endpoint
->IsOutput())
143 ((BUSBInterface
*)interface
)->SetAlternate(alt
);
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
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())
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
,
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
);
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
);
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!
218 USBPrinter::Write(const void *buf
, size_t size
)
220 if (!buf
|| size
<= 0)
223 // NOTE: we can safely cast below as we're sending data _out_
224 return fOut
->BulkTransfer((void*)buf
, size
);
229 USBPrinter::Read(void *buf
, size_t size
)
231 if (!buf
|| size
<= 0)
234 return fIn
->BulkTransfer(buf
, size
);
238 // Implementation of transport add-on interface
241 instantiate_transport(BDirectory
*printer
, BMessage
*msg
)
243 USBTransport
*transport
= new(std::nothrow
) USBTransport(printer
, msg
);
244 if (transport
!= NULL
&& transport
->InitCheck() == B_OK
)
252 // List detected printers
254 list_transport_ports(BMessage
*msg
)
256 USBPrinterRoster roster
;
257 status_t status
= roster
.ListPrinters(msg
);
263 // Implementation of USBTransport
264 USBTransport::USBTransport(BDirectory
*printer
, BMessage
*msg
)
269 if (printer
->ReadAttrString("transport_address", &key
) != B_OK
)
272 fRoster
= new(std::nothrow
) USBPrinterRoster
;
276 fPrinter
= fRoster
->Printer(key
.String());
277 if (fPrinter
== NULL
)
280 // If caller doesn't care...
284 // Fill up the message
289 USBTransport::~USBTransport()
291 if (fRoster
!= NULL
) {
299 USBTransport::Read(void *buffer
, size_t size
)
301 return fPrinter
? fPrinter
->Read(buffer
, size
) : B_ERROR
;
306 USBTransport::Write(const void *buffer
, size_t size
)
308 return fPrinter
? fPrinter
->Write(buffer
, size
) : B_ERROR
;