USB打印机固件
本文地址:http://tongxinmao.com/Article/Detail/id/73
http://www.microchip.com/forums/m491016.aspx
Printer Class
Printer Device Class Document 1.1
IPP Protocol 1.0 and Adopters Agreement (.zip, 1.32 MB)
// add these definitions
/* Printer class */
#define PRINTER_INTF_ID 0
#define PRINTER_EP_NUM 1
#define PRINTER_EP_OUT_SIZE 64
#define PRINTER_EP_IN_SIZE 64
usb_descriptor.c
#ifndef __USB_DESCRIPTORS_C
#define __USB_DESCRIPTORS_C
/** INCLUDES *******************************************************/
#include "./USB/usb.h"
/** CONSTANTS ******************************************************/
#if defined(__18CXX)
#pragma romdata
#endif
/* Device Descriptor */
ROM USB_DEVICE_DESCRIPTOR device_dsc=
{
0x12, // Size of this descriptor in bytes
USB_DESCRIPTOR_DEVICE, // DEVICE descriptor type
0x0200, // USB Spec Release Number in BCD format
0x00, // Class Code
0x00, // Subclass code
0x00, // Protocol code
USB_EP0_BUFF_SIZE, // Max packet size for EP0, see usb_config.h
0xFF07, // Vendor ID: temporary for development
0x0100, // Product ID:
0x0000, // Device release number in BCD format
0x01, // Manufacturer string index
0x02, // Product string index
0x03, // Device serial number string index
0x01 // Number of possible configurations
};
/* Configuration 1 Descriptor */
ROM BYTE configDescriptor1[]={
// Configuration Descriptor
0x09, //sizeof(USB_CFG_DSC), // Size of this descriptor in bytes
USB_DESCRIPTOR_CONFIGURATION, // CONFIGURATION descriptor type
0x20,0x00, // Total length of data for this cfg
1, // Number of interfaces in this cfg
1, // Index value of this configuration
0, // Configuration string index
_DEFAULT | _SELF, // Attributes, see usb_device.h
50, // Max power consumption (2X mA)
// Interface Descriptor
0x09, //sizeof(USB_INTF_DSC), // Size of this descriptor in bytes
USB_DESCRIPTOR_INTERFACE, // INTERFACE descriptor type
PRINTER_INTF_ID, // Interface Index
0, // Alternate Setting Number
2, // Number of endpoints in this intf
0x07, // Class code : Printers
0x01, // Subclass code: Printers
0x03, // Protocol code: 1284.4 compatible bi-directional
0, // Interface string index
// Endpoint Descriptor
0x07, //sizeof(USB_EP_DSC)
USB_DESCRIPTOR_ENDPOINT, //Endpoint Descriptor
PRINTER_EP_NUM | _EP_OUT, //EndpointAddress
_BULK, //Attributes
PRINTER_EP_OUT_SIZE,0x00, //size
1, //Interval
// Endpoint Descriptor
0x07, //sizeof(USB_EP_DSC)
USB_DESCRIPTOR_ENDPOINT, //Endpoint Descriptor
PRINTER_EP_NUM | _EP_IN, //EndpointAddress
_BULK, //Attributes
PRINTER_EP_IN_SIZE,0x00, //size
1, //Interval
};
//Language code string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[1];}sd000={
sizeof(sd000),USB_DESCRIPTOR_STRING,{0x0409}};
//Manufacturer string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[25];}sd001={
sizeof(sd001),USB_DESCRIPTOR_STRING,
{'M','i','c','r','o','c','h','i','p',' ',
'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'
}};
//Product string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[32];}sd002={
sizeof(sd002),USB_DESCRIPTOR_STRING,
{'M','i','c','r','o','c','h','i','p',' ','P','r','i','n','t','e','r',
' ','E','x','a','m','p','l','e',' ','D','e','v','i','c','e'}};
//Serial number string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[4];}sd003={
sizeof(sd003),USB_DESCRIPTOR_STRING,
{'0','0','0','1',}};
//Array of configuration descriptors
ROM BYTE *ROM USB_CD_Ptr[]=
{
(ROM BYTE *ROM)&configDescriptor1
};
//Array of string descriptors
ROM BYTE *ROM USB_SD_Ptr[]=
{
(ROM BYTE *ROM)&sd000,
(ROM BYTE *ROM)&sd001,
(ROM BYTE *ROM)&sd002,
(ROM BYTE *ROM)&sd003
};
/** EOF usb_descriptors.c ***************************************************/
#endif
main.c
USB_VOLATILE BOOL prn_flag_soft_reset = FALSE;
void ProcessIO(void)
{
// Blink the LEDs according to the USB device status,
// but only do so if the PC application isn't connected
// and controlling the LEDs.
if(blinkStatusValid)
{
BlinkUSBStatus();
}
if( (USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1) ) return;
// a packet comes from host
if( !USBHandleBusy( USBGenericOutHandle ) )
{
BYTE received_num;
received_num = USBHandleGetLength( USBGenericOutHandle ); // number of data bytes on OUTPacket[]
//
// process data on OUTPacket[] here
//
// pass the buffer to USB engine for next packet
USBGenericOutHandle = USBGenRead( PRINTER_EP_NUM, (BYTE*)&OUTPacket, PRINTER_EP_OUT_SIZE );
}
// Soft_Reset comes from host
if ( prn_flag_soft_reset ) {
prn_flag_soft_reset = FALSE;
//
// Stop current print process
// Clear printer buffer, if any
//
}
}//end ProcessIO
void USBCBInitEP(void)
{
USBEnableEndpoint( PRINTER_EP_NUM, USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP );
USBGenericOutHandle = USBGenRead( PRINTER_EP_NUM, OUTPacket, PRINTER_EP_OUT_SIZE );
prn_flag_soft_reset = FALSE;
}
void USBCheckPrinterRequest( void ); // prototype
void USBCBCheckOtherReq( void )
{
USBCheckPrinterRequest();
}
//
// class-specific request handlers for printer
//
// external global variables
extern volatile CTRL_TRF_SETUP SetupPkt;
extern volatile BYTE CtrlTrfData[];
extern volatile BDT_ENTRY *pBDTEntryOut[];
// definition of USB_NEXT_PING_PONG - copied from usb_device.c
#if (USB_PING_PONG_MODE == USB_PING_PONG__NO_PING_PONG)
#define USB_NEXT_PING_PONG 0x0000
#elif (USB_PING_PONG_MODE == USB_PING_PONG__EP0_OUT_ONLY)
#define USB_NEXT_PING_PONG 0x0000
#elif (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG)
#if defined (__18CXX) || defined(__C30__)
#define USB_NEXT_PING_PONG 0x0004
#elif defined(__C32__)
#define USB_NEXT_PING_PONG 0x0008
#else
#error "Not defined for this compiler"
#endif
#elif (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0)
#define USB_NEXT_PING_PONG 0x0004
#else
#error "No ping pong mode defined."
#endif
// bRequest value for printer class-specific requests
enum {
PRNT_GET_DEVICE_ID = 0,
PRNT_GET_PORT_STATUS = 1,
PRNT_SOFT_RESET = 2
};
// Port Status bitmap
typedef union __attribute__ ((packed))
{
BYTE b;
struct __attribute__ ((packed))
{
unsigned :3;
unsigned prn_not_error :1;
unsigned prn_select :1;
unsigned prn_paper_empty :1;
unsigned :2;
};
} T_prn_port_status;
// Device ID string
// see these links for the details
// http://www.undocprint.org/formats/communication_protocols/ieee_1284
// http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/pnplpt.rtf
typedef struct __attribute__ ((packed))
{
BYTE size_h, size_l;
BYTE str[];
} T_prn_Device_ID;
static ROM T_prn_Device_ID prn_Device_ID =
{
0x00, 14 + 15 + 11 + 12 + 20, // size of string, two-bytes, MSB first
{ // these strings are concatenated by compiler
"MFG:MICROCHIP;" // manufacturer
"MDL:MCHP-PR001;" // model
"CMD:1284.4;" // PDL command set
"CLS:PRINTER;" // class
"DES:MICROCHIP PR001;" // description
// "CID:LPTENUM\Hewlett-PackardHP_La847D" // compatible ID: HP LaserJet 1200
}
};
void USBCheckPrinterRequest( void )
{
// Get_Device_ID
if ( (SetupPkt.bmRequestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE))
&& (SetupPkt.bRequest == PRNT_GET_DEVICE_ID)
&& (SetupPkt.wValue == 0) // config index (start with 0, == bConfigurationValue - 1)
&& (SetupPkt.bIntfID == 0) // alternate interface
&& (SetupPkt.bIntfID_H == PRINTER_INTF_ID) // interface number, bInterfaceNumber
) {
// pass the Device ID string except for the last '\0'
USBEP0SendROMPtr( (ROM BYTE *)&prn_Device_ID, prn_Device_ID.size_l + 2, USB_EP0_INCLUDE_ZERO );
}
// Get_Port_Status
if ( (SetupPkt.bmRequestType == (USB_SETUP_DEVICE_TO_HOST | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE))
&& (SetupPkt.bRequest == PRNT_GET_PORT_STATUS)
&& (SetupPkt.wValue == 0) // must be zero
&& (SetupPkt.wIndex == PRINTER_INTF_ID) // interface number, bInterfaceNumber
&& (SetupPkt.wLength == 1) // size of reply: must be 1
) {
T_prn_port_status port_status;
port_status.b = 0; // initialize status bitmap
port_status.prn_not_error = 1; // 1 = No Error, 0 = Error
port_status.prn_select = 1; // 1 = Selected, 0 = Not Selected
port_status.prn_paper_empty = 0; // 1 = Paper Empty, 0 = Paper Not Empty
CtrlTrfData[0] = port_status.b; // pass the status to the stack
USBEP0SendRAMPtr( CtrlTrfData, 1, USB_EP0_INCLUDE_ZERO );
}
// Soft_Reset
if (((SetupPkt.bmRequestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_INTERFACE))
|| (SetupPkt.bmRequestType == (USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_CLASS | USB_SETUP_RECIPIENT_OTHER)))
&& (SetupPkt.bRequest == PRNT_SOFT_RESET)
&& (SetupPkt.wValue == 0) // must be zero
&& (SetupPkt.wIndex == PRINTER_INTF_ID) // interface number, bInterfaceNumber
&& (SetupPkt.wLength == 0) // must be zero
) {
BDT_ENTRY *p;
// if the bulk endpint is stalled, recover it
#if defined(__C32__)
DWORD* pUEP;
pUEP = (DWORD*)(&U1EP0);
pUEP += (PRINTER_EP_NUM*4);
#else
unsigned char* pUEP;
pUEP = (unsigned char*)(&U1EP0+PRINTER_EP_NUM);
#endif
if ( *pUEP & UEP_STALL ) {
*pUEP &= ~UEP_STALL; // Clear EPSTALL bit in the UEP register
// Clear BSTALL bit on BDnSTAT for OUT endpoint
p = pBDTEntryOut[PRINTER_EP_NUM];
#if (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) || (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG)
p->STAT.Val = _USIE|_DAT0|_DTSEN;
((BYTE_VAL*)&p)->Val ^= USB_NEXT_PING_PONG; //toggle over to the next buffer
p->STAT.Val = _USIE|_DAT1|_DTSEN;
#else
p->STAT.Val = _USIE|_DAT1|_DTSEN;
#endif
// Clear BSTALL bit on BDnSTAT for IN endpoint
p = pBDTEntryIn[PRINTER_EP_NUM];
#if (USB_PING_PONG_MODE == USB_PING_PONG__ALL_BUT_EP0) || (USB_PING_PONG_MODE == USB_PING_PONG__FULL_PING_PONG)
p->STAT.Val = _UCPU|_DAT0;
((BYTE_VAL*)&p)->Val ^= USB_NEXT_PING_PONG; //toggle over the to the next buffer
p->STAT.Val = _UCPU|_DAT1;
#else
p->STAT.Val = _UCPU|_DAT1;
#endif
}
// discard and pass the buffer
if( !USBHandleBusy( USBGenericOutHandle ) ) {
USBGenericOutHandle = USBGenRead( PRINTER_EP_NUM, (BYTE*)&OUTPacket, PRINTER_EP_OUT_SIZE );
}
prn_flag_soft_reset = TRUE;
USBEP0Transmit( USB_EP0_NO_DATA ); // report success on STATUS stage
}
}
It's a good idea.
I've investigated Windows default INF files a little more, and found these clues.
a) Windows have two default INF for USB printer class (class_07)
usbprint.inf - USB\Class_07
dot4.inf - USB\Class_07&SubClass_01&Prot_03
When dot4.inf is applied, driver installation is interractive, not automatically.
usbprint.inf
[Microsoft]
%USBPRINT.DeviceDesc% = USBPRINT_Inst,USB\Class_07,GENERIC_USB_PRINTER
dot4.inf
[ControlFlags]
ExcludeFromSelect = *
InteractiveInstall = USB\Class_07&SubClass_01&Prot_03
[MS_Models]
%DOT4USB.DeviceDesc% = DOT4USB_Inst,USB\Class_07&SubClass_01&Prot_03,GENERIC_USB_PRINTER
b) Generic text-only printer is defined in another default INF, as follows.
ntprint.inf
[Generic]
"Generic / Text Only" = TTY.GPD ,GenericGeneric_/_Tex8040,Generic_/_Text_Only
According to this MS document,
http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/pnplpt.rtf
this device ID on the INF is generated by these manufacturer and model fields of printer "Device ID" string. (revised)
MFG:Generic;
MDL:Generic_/_Text_Only;
Now that we know these facts, modify above code as follows.
a) To apply usbprint.inf silently on installation, change InterfaceProtocol value on the interface descriptor, from 3 (1284.4) to 2 (generic bi-directional)
// Interface Descriptor
0x09, //sizeof(USB_INTF_DSC), // Size of this descriptor in bytes
USB_DESCRIPTOR_INTERFACE, // INTERFACE descriptor type
PRINTER_INTF_ID, // Interface Index
0, // Alternate Setting Number
2, // Number of endpoints in this intf
0x07, // Class code : Printers
0x01, // Subclass code: Printers
0x02, // Protocol code: bi-directional <---------------
0, // Interface string index
b) To assign "Generic / Text Only" driver silently, change printer device ID string as follows. (revised)
static ROM T_prn_Device_ID prn_Device_ID =
{
0x00, 12 + 24 + 11 + 12 + 30, // size of string, two-bytes, MSB first
{ // these strings are concatenated by compiler
"MFG:Generic;" // manufacturer (case sensitive)
"MDL:Generic_/_Text_Only;" // model (case sensitive)
"CMD:1284.4;" // PDL command set
"CLS:PRINTER;" // class
"DES:Generic text only printer;" // description
}
};
In my above post, I've mistakenly posted printer ID string (already revised)
The actual printer ID string for text-only is as follows.
MFG:Generic;
MDL:Generic_/_Text_Only;
Also, the code for prn_Device_ID was revised.
It's case sensitive, and with underscore.
With this modification, the printer firmware is recognized by Windows silently (except for tray pop-up).
If you've tried the wrong string, sorry for your inconvenience.
Tsuneo
上一篇:Altium Designer技巧
下一篇:如何使用8位单片机设计一款灵活的低成本血糖仪