* Switch to using USBKit instead of usb_printer kernel driver

* Implement new transport id/name listing



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36115 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ithamar R. Adema 2010-04-10 17:12:31 +00:00
parent 77b2080187
commit c52f7982c9
2 changed files with 217 additions and 114 deletions

View File

@ -2,14 +2,14 @@ SubDir HAIKU_TOP src add-ons print transports usb_port ;
SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders print ;
UsePrivateHeaders shared print ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits print ] ;
Addon USB\ Port :
USBTransport.cpp
PrintTransportAddOn.cpp
: be $(TARGET_LIBSUPC++)
: libshared.a libdevice.so be $(TARGET_LIBSUPC++)
;
Package haiku-printingkit-cvs :

View File

@ -1,50 +1,68 @@
/*****************************************************************************/
// USB port transport add-on,
// changes by Andreas Benzler, Philippe Houdoin
//
// Original from Parallel
// port transport add-on.
//
// Author
// Michael Pfeiffer
//
// This application and all source files used in its construction, except
// where noted, are licensed under the MIT License, and have been written
// and are:
//
// Copyright (c) 2001-2004 OpenBeOS Project
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
/*****************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <StorageKit.h>
#include <SupportKit.h>
#include <USB_printer.h>
/*
* Copyright 2001-2010 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Originally written based on Parallel port addon by Michael Pfeiffer,
* changes by Andreas Benzler, Philippe Houdoin
* Rewritten to use the USBKit by Ithamar R. Adema.
* (Using code from usb_printer.cpp by Michael Lotz)
*
* Authors:
* Ithamar R. Adema, <ithamar.adema@team-embedded.nl>
* Michael Pfeiffer,
* Andreas Benzler,
* Philippe Houdoin,
*/
#include "PrintTransportAddOn.h"
#include <USBKit.h>
#include <String.h>
#include <HashString.h>
#include <HashMap.h>
#define PRINTER_INTERFACE_CLASS 0x07
#define PRINTER_INTERFACE_SUBCLASS 0x01
// printer interface types
#define PIT_UNIDIRECTIONAL 0x01
#define PIT_BIDIRECTIONAL 0x02
#define PIT_1284_4_COMPATIBLE 0x03
#define PIT_VENDOR_SPECIFIC 0xff
class USBPrinter
{
public:
USBPrinter(const BString& id, const BString& name,
const BUSBInterface *intf, const BUSBEndpoint* in, const BUSBEndpoint* out);
ssize_t Write(const void *buf, size_t size);
ssize_t Read(void *buf, size_t size);
const BUSBInterface *fInterface;
const BUSBEndpoint *fOut;
const BUSBEndpoint *fIn;
BString fName;
BString fID;
};
class USBPrinterRoster : public BUSBRoster {
public:
USBPrinterRoster();
status_t DeviceAdded(BUSBDevice* dev);
void DeviceRemoved(BUSBDevice* dev);
USBPrinter *Printer(const BString& key);
status_t ListPrinters(BMessage *msg);
private:
typedef HashMap<HashString,USBPrinter*> PrinterMap;
PrinterMap fPrinters;
};
class USBTransport : public BDataIO
{
@ -52,16 +70,152 @@ public:
USBTransport(BDirectory *printer, BMessage *msg);
~USBTransport();
status_t InitCheck() { return fFile > -1 ? B_OK : B_ERROR; };
status_t InitCheck() { return fPrinter ? B_OK : B_ERROR; };
ssize_t Read(void *buffer, size_t size);
ssize_t Write(const void *buffer, size_t size);
private:
int fFile;
USBPrinter *fPrinter;
};
// Set transport_features so we stay loaded
uint32 transport_features = B_TRANSPORT_IS_HOTPLUG;
USBPrinterRoster gUSBPrinterRoster;
USBPrinterRoster::USBPrinterRoster()
{
Start();
}
USBPrinter *USBPrinterRoster::Printer(const BString& key)
{
if (fPrinters.ContainsKey(key.String()))
return fPrinters.Get(key.String());
return NULL;
}
status_t USBPrinterRoster::DeviceAdded(BUSBDevice* dev)
{
const BUSBConfiguration *cfg = dev->ActiveConfiguration();
const BUSBEndpoint *in = NULL, *out = NULL;
const BUSBInterface *printer = NULL;
// Try to find a working printer interface in this device
if (cfg) {
for (uint32 idx=0; printer == NULL && idx < cfg->CountInterfaces(); idx++) {
const BUSBInterface *intf=cfg->InterfaceAt(idx);
if (intf->Class() == PRINTER_INTERFACE_CLASS &&
intf->Subclass() == PRINTER_INTERFACE_SUBCLASS &&
(intf->Protocol() == PIT_UNIDIRECTIONAL ||
intf->Protocol() == PIT_BIDIRECTIONAL ||
intf->Protocol() == PIT_1284_4_COMPATIBLE)) {
// Found a usable Printer interface!
for (uint32 eptidx=0; eptidx < intf->CountEndpoints(); eptidx++) {
const BUSBEndpoint *ept = intf->EndpointAt(eptidx);
if (!ept->IsBulk())
continue;
if (ept->IsInput())
in = ept;
else if (ept->IsOutput())
out = ept;
if (!in || !out)
continue;
printer = intf;
break;
}
}
}
}
if (printer != NULL) {
// We found a working printer interface, lets determine a unique ID
// for it now, and a user identification for display in the Printers
// preference.
BString port_id = dev->SerialNumberString();
if (!port_id.Length()) {
// No persistent unique ID available, use the vendor/product
// ID for now. This will be unique as long as no two similar
// devices are attached.
port_id << dev->VendorID() << "/" << dev->ProductID();
}
BString port_name = dev->ManufacturerString();
if (port_name.Length())
port_name << " ";
port_name << dev->ProductString();
//TODO: Do we want to use usb.ids to find proper name if strings
// are not supplied by USB?
fPrinters.Put(port_id.String(), new USBPrinter(port_id, port_name,
printer, in, out));
}
return B_OK;
}
void USBPrinterRoster::DeviceRemoved(BUSBDevice* dev)
{
PrinterMap::Iterator iterator = fPrinters.GetIterator();
while (iterator.HasNext()) {
const PrinterMap::Entry& entry = iterator.Next();
// If the device is in the list, remove it
if (entry.value->fInterface->Device() == dev) {
fPrinters.Remove(entry.key);
delete entry.value;
break;
}
}
}
status_t USBPrinterRoster::ListPrinters(BMessage* msg)
{
PrinterMap::Iterator iterator = fPrinters.GetIterator();
while (iterator.HasNext()) {
const PrinterMap::Entry& entry = iterator.Next();
msg->AddString("port_id", entry.value->fID);
msg->AddString("port_name", entry.value->fName);
}
return B_OK;
}
USBPrinter::USBPrinter(const BString& id, const BString& name,
const BUSBInterface *intf, const BUSBEndpoint* in, const BUSBEndpoint* out)
: fInterface(intf), fOut(out), fIn(in), fName(name), fID(id)
{
}
//TODO: see usb_printer.cpp for error handling during read/write!
ssize_t USBPrinter::Write(const void *buf, size_t size)
{
if (!buf || size <= 0)
return B_BAD_VALUE;
// NOTE: we can safely cast below as we're sending data _out_
return fOut->BulkTransfer((void*)buf, size);
}
ssize_t USBPrinter::Read(void *buf, size_t size)
{
if (!buf || size <= 0)
return B_BAD_VALUE;
return fIn->BulkTransfer(buf, size);
}
// Implementation of transport add-on interface
BDataIO *
@ -75,99 +229,48 @@ instantiate_transport(BDirectory *printer, BMessage *msg)
return NULL;
}
// List detected printers
status_t list_transport_ports(BMessage* msg)
{
BDirectory dir("/dev/printer/usb");
status_t rc;
if ((rc=dir.InitCheck()) != B_OK)
return rc;
if ((rc=dir.Rewind()) != B_OK)
return rc;
entry_ref ref;
while(dir.GetNextRef(&ref) == B_OK)
msg->AddString("port_id", ref.name);
return B_OK;
return gUSBPrinterRoster.ListPrinters(msg);
}
// Implementation of USBTransport
USBTransport::USBTransport(BDirectory *printer, BMessage *msg)
: fFile(-1)
: fPrinter(NULL)
{
char device_id[USB_PRINTER_DEVICE_ID_LENGTH + 1];
char name[USB_PRINTER_DEVICE_ID_LENGTH + 1];
char *desc;
char *value;
int ret;
bool bidirectional = true;
char *next_token;
// We support only one USB printer, so does BeOS R5.
fFile = open("/dev/printer/usb/0", O_RDWR | O_EXCL | O_BINARY, 0);
if (fFile < 0) {
// Try unidirectional access mode
bidirectional = false;
fFile = open("/dev/printer/usb/0", O_WRONLY | O_EXCL | O_BINARY, 0);
}
if (fFile < 0)
BString key;
if (printer->ReadAttrString("transport_address", &key) < 0)
return;
// Get printer's DEVICE ID string
ret = ioctl(fFile, USB_PRINTER_GET_DEVICE_ID, device_id, sizeof(device_id));
if (ret < 0) {
close(fFile);
fFile = -1;
fPrinter = gUSBPrinterRoster.Printer(key.String());
if (!fPrinter)
return;
}
if (! msg)
// Caller don't care about transport init message output content...
// If caller doesn't care...
if (!msg)
return;
// Fill up the message
msg->what = 'okok';
msg->AddBool("bidirectional", bidirectional);
msg->AddString("device_id", device_id);
// parse and split the device_id string into separate parameters
desc = strtok_r(device_id, ":", &next_token);
while (desc) {
snprintf(name, sizeof(name), "DEVID:%s", desc);
value = strtok_r(NULL, ";", &next_token);
if (!value)
break;
msg->AddString(name, value);
// next device descriptor
desc = strtok_r(NULL, ":", &next_token);
}
}
USBTransport::~USBTransport()
{
if (fFile > -1)
close(fFile);
}
ssize_t
USBTransport::Read(void *buffer, size_t size)
{
return read(fFile, buffer, size);
return fPrinter ? fPrinter->Read(buffer, size) : B_ERROR;
}
ssize_t
USBTransport::Write(const void *buffer, size_t size)
{
return write(fFile, buffer, size);
return fPrinter ? fPrinter->Write(buffer, size) : B_ERROR;
}